diff --git a/BUILD.gn b/BUILD.gn index 662dea5..5d692b4b 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -188,7 +188,7 @@ "//chrome/test:telemetry_perf_unittests", "//chrome/test:unit_tests", "//components:components_browsertests", - "//components/ui_devtools/viz_views", + "//components/ui_devtools/viz", "//components/viz:viz_perftests", "//components/viz:viz_unittests", "//components/viz/common:viz_benchmark",
diff --git a/DEPS b/DEPS index 79132286..1ead8ca 100644 --- a/DEPS +++ b/DEPS
@@ -117,15 +117,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling sfntly # and whatever else without interference from each other. - 'sfntly_revision': 'b55ff303ea2f9e26702b514cf6a3196a2e3e2974', + 'sfntly_revision': 'e24c73130c663c9f329e78f5ca3fd5bd83b02622', # 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': 'a9a06907f39c5c771c33a6101f97fce613f674b8', + 'skia_revision': 'f1202c61de0875f38dfe3c93ec99a08b9c625cc7', # 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': '336755dcde17709b01b76af34da2e6f898bbdfac', + 'v8_revision': 'dadf4cbe89c1e9ee9fed6181216cb4d3ba647a68', # 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. @@ -133,7 +133,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': '6344d8ea30d7a5ce14042cdd4dcf90a53107b9e5', + 'angle_revision': '988d9a068976cd893eb1cd1093299b166b58594a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling build tools # and whatever else without interference from each other. @@ -145,7 +145,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': '800298c07d246b4235ef7cd699a75271e6904c61', + 'pdfium_revision': '45531b950b6a04a7bcae12431ccfebec9aec77d6', # 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. @@ -181,7 +181,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '4dbf1ef8fd93fd90aa85fb7739736fa25d226187', + 'catapult_revision': '3511bed449613cd4dc1231eedf29f2d8a5423d7e', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -679,7 +679,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '82b851dfd6665ba6452703654b3f8adbcbc2c565', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'af1fe10f99b95a23575cc9db6a30c0c1f26b1fa3', 'condition': 'checkout_linux', }, @@ -1230,7 +1230,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@14b74af5cc204ee9cd89a51aef9556d05f8636d8', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@05b6bde0074d047c78884a00904b44e1de47d19e', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index a2aadee..3d79a67f 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -276,6 +276,20 @@ network::mojom::NetworkContextPtr network_context; network::mojom::NetworkContextParamsPtr context_params = + GetNetworkContextParams(); + + content::GetNetworkService()->CreateNetworkContext( + MakeRequest(&network_context), std::move(context_params)); + + // Quic is not currently supported in WebView. + content::GetNetworkService()->DisableQuic(); + + return network_context; +} + +network::mojom::NetworkContextParamsPtr +AwContentBrowserClient::GetNetworkContextParams() { + network::mojom::NetworkContextParamsPtr context_params = network::mojom::NetworkContextParams::New(); context_params->user_agent = GetUserAgent(); // TODO(ntfschr): set this value to a proper value based on the user's @@ -289,19 +303,21 @@ context_params->http_cache_max_size = GetHttpCacheSize(); context_params->http_cache_path = AwBrowserContext::GetCacheDir(); + context_params->initial_ssl_config = network::mojom::SSLConfig::New(); + // Allow SHA-1 to be used for locally-installed trust anchors, as WebView + // should behave like the Android system would. + context_params->initial_ssl_config->sha1_local_anchors_enabled = true; + // Do not enforce the Legacy Symantec PKI policies outlined in + // https://security.googleblog.com/2017/09/chromes-plan-to-distrust-symantec.html, + // defer to the Android system. + context_params->initial_ssl_config->symantec_enforcement_disabled = true; + // WebView does not currently support Certificate Transparency. context_params->enforce_chrome_ct_policy = false; // WebView does not support ftp yet. context_params->enable_ftp_url_support = false; - - content::GetNetworkService()->CreateNetworkContext( - MakeRequest(&network_context), std::move(context_params)); - - // Quic is not currently supported in WebView. - content::GetNetworkService()->DisableQuic(); - - return network_context; + return context_params; } AwBrowserContext* AwContentBrowserClient::InitBrowserContext() {
diff --git a/android_webview/browser/aw_content_browser_client.h b/android_webview/browser/aw_content_browser_client.h index 08ef1d7..5fa0fce 100644 --- a/android_webview/browser/aw_content_browser_client.h +++ b/android_webview/browser/aw_content_browser_client.h
@@ -58,6 +58,7 @@ content::BrowserContext* context, bool in_memory, const base::FilePath& relative_partition_path) override; + network::mojom::NetworkContextParamsPtr GetNetworkContextParams(); content::BrowserMainParts* CreateBrowserMainParts( const content::MainFunctionParams& parameters) override;
diff --git a/android_webview/browser/aw_content_browser_client_unittest.cc b/android_webview/browser/aw_content_browser_client_unittest.cc index 462075e..e72a1927 100644 --- a/android_webview/browser/aw_content_browser_client_unittest.cc +++ b/android_webview/browser/aw_content_browser_client_unittest.cc
@@ -19,4 +19,33 @@ EXPECT_FALSE(client.ShouldCreateTaskScheduler()); } +// Tests that constraints on trust for Symantec-issued certificates are not +// enforced for the NetworkContext, as it should behave like the Android system. +TEST_F(AwContentBrowserClientTest, SymantecPoliciesExempted) { + AwFeatureListCreator aw_feature_list_creator; + AwContentBrowserClient client(&aw_feature_list_creator); + network::mojom::NetworkContextParamsPtr network_context_params = + client.GetNetworkContextParams(); + + ASSERT_TRUE(network_context_params); + ASSERT_TRUE(network_context_params->initial_ssl_config); + ASSERT_TRUE(network_context_params->initial_ssl_config + ->symantec_enforcement_disabled); +} + +// Tests that SHA-1 is still allowed for locally-installed trust anchors, +// including those in application manifests, as it should behave like +// the Android system. +TEST_F(AwContentBrowserClientTest, SHA1LocalAnchorsAllowed) { + AwFeatureListCreator aw_feature_list_creator; + AwContentBrowserClient client(&aw_feature_list_creator); + network::mojom::NetworkContextParamsPtr network_context_params = + client.GetNetworkContextParams(); + + ASSERT_TRUE(network_context_params); + ASSERT_TRUE(network_context_params->initial_ssl_config); + ASSERT_TRUE( + network_context_params->initial_ssl_config->sha1_local_anchors_enabled); +} + } // namespace android_webview
diff --git a/android_webview/browser/compositor_frame_producer.h b/android_webview/browser/compositor_frame_producer.h index c0c6f52..a207c4d 100644 --- a/android_webview/browser/compositor_frame_producer.h +++ b/android_webview/browser/compositor_frame_producer.h
@@ -17,7 +17,7 @@ class CompositorFrameProducer { public: - virtual base::WeakPtr<CompositorFrameProducer> GetWeakPtr(); + virtual base::WeakPtr<CompositorFrameProducer> GetWeakPtr() = 0; virtual void ReturnUsedResources( const std::vector<viz::ReturnedResource>& resources, const CompositorID& compositor_id,
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java new file mode 100644 index 0000000..96b6863 --- /dev/null +++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java
@@ -0,0 +1,68 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview.test; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.android_webview.AwContents; +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.Feature; +import org.chromium.net.test.EmbeddedTestServer; +import org.chromium.net.test.ServerCertificate; + +/** + * A test suite for WebView's network-related configuration. This tests WebView's default settings, + * which are configured by either AwURLRequestContextGetter or NetworkContext. + */ +@RunWith(AwJUnit4ClassRunner.class) +public class AwNetworkConfigurationTest { + @Rule + public AwActivityTestRule mActivityTestRule = new AwActivityTestRule(); + + private AwTestContainerView mTestContainerView; + private TestAwContentsClient mContentsClient; + private AwTestContainerView mContainerView; + private AwContents mAwContents; + + private EmbeddedTestServer mTestServer; + + @Before + public void setUp() throws Exception { + mContentsClient = new TestAwContentsClient(); + mTestContainerView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient); + mAwContents = mTestContainerView.getAwContents(); + } + + @Test + @SmallTest + @Feature({"AndroidWebView", "Network"}) + public void testSHA1LocalAnchorsAllowed() throws Throwable { + mTestServer = EmbeddedTestServer.createAndStartHTTPSServer( + InstrumentationRegistry.getInstrumentation().getContext(), + ServerCertificate.CERT_SHA1_LEAF); + try { + CallbackHelper onReceivedSslErrorHelper = mContentsClient.getOnReceivedSslErrorHelper(); + int count = onReceivedSslErrorHelper.getCallCount(); + String url = mTestServer.getURL("/android_webview/test/data/hello_world.html"); + mActivityTestRule.loadUrlSync( + mAwContents, mContentsClient.getOnPageFinishedHelper(), url); + // TODO(ntfschr): update this assertion whenever + // https://android.googlesource.com/platform/external/conscrypt/+/1d6a0b8453054b7dd703693f2ce2896ae061aee3 + // rolls into an Android release, as this will mean Android intends to distrust SHA1 + // (http://crbug.com/919749). + Assert.assertEquals("We should not have received any SSL errors", count, + onReceivedSslErrorHelper.getCallCount()); + } finally { + mTestServer.stopAndDestroyServer(); + } + } +}
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index 8e6f6b3..beb8f2e 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -211,6 +211,7 @@ "../javatests/src/org/chromium/android_webview/test/AwJavaBridgeTest.java", "../javatests/src/org/chromium/android_webview/test/AwLayoutSizerTest.java", "../javatests/src/org/chromium/android_webview/test/AwLegacyQuirksTest.java", + "../javatests/src/org/chromium/android_webview/test/AwNetworkConfigurationTest.java", "../javatests/src/org/chromium/android_webview/test/AwPermissionManagerTest.java", "../javatests/src/org/chromium/android_webview/test/AwQuotaManagerBridgeTest.java", "../javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java",
diff --git a/ash/accessibility/accessibility_controller.cc b/ash/accessibility/accessibility_controller.cc index 78e45d2..6489aff 100644 --- a/ash/accessibility/accessibility_controller.cc +++ b/ash/accessibility/accessibility_controller.cc
@@ -595,6 +595,11 @@ switch_access_event_handler_->set_ignore_virtual_key_events(should_ignore); } +void AccessibilityController::ForwardKeyEventsToSwitchAccess( + bool should_forward) { + switch_access_event_handler_->set_forward_key_events(should_forward); +} + void AccessibilityController::SetSwitchAccessEventHandlerDelegate( mojom::SwitchAccessEventHandlerDelegatePtr delegate) { switch_access_event_handler_delegate_ptr_ = std::move(delegate);
diff --git a/ash/accessibility/accessibility_controller.h b/ash/accessibility/accessibility_controller.h index 4863985..a94d275b 100644 --- a/ash/accessibility/accessibility_controller.h +++ b/ash/accessibility/accessibility_controller.h
@@ -182,6 +182,7 @@ void SetSwitchAccessEventHandlerDelegate( mojom::SwitchAccessEventHandlerDelegatePtr delegate) override; void ToggleDictationFromSource(mojom::DictationToggleSource source) override; + void ForwardKeyEventsToSwitchAccess(bool should_forward) override; // SessionObserver: void OnSigninScreenPrefServiceInitialized(PrefService* prefs) override;
diff --git a/ash/app_list/BUILD.gn b/ash/app_list/BUILD.gn index ff72324..fdedfee 100644 --- a/ash/app_list/BUILD.gn +++ b/ash/app_list/BUILD.gn
@@ -86,8 +86,6 @@ "views/suggestion_chip_container_view.h", "views/suggestion_chip_view.cc", "views/suggestion_chip_view.h", - "views/suggestions_container_view.cc", - "views/suggestions_container_view.h", "views/top_icon_animation_view.cc", "views/top_icon_animation_view.h", ]
diff --git a/ash/app_list/views/app_list_view_unittest.cc b/ash/app_list/views/app_list_view_unittest.cc index b7baf50..23f7b75 100644 --- a/ash/app_list/views/app_list_view_unittest.cc +++ b/ash/app_list/views/app_list_view_unittest.cc
@@ -35,7 +35,6 @@ #include "ash/app_list/views/search_result_view.h" #include "ash/app_list/views/suggestion_chip_container_view.h" #include "ash/app_list/views/suggestion_chip_view.h" -#include "ash/app_list/views/suggestions_container_view.h" #include "ash/app_list/views/test/apps_grid_view_test_api.h" #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_constants.h"
diff --git a/ash/app_list/views/apps_container_view.cc b/ash/app_list/views/apps_container_view.cc index 7339e13..b3f2d966 100644 --- a/ash/app_list/views/apps_container_view.cc +++ b/ash/app_list/views/apps_container_view.cc
@@ -18,7 +18,6 @@ #include "ash/app_list/views/page_switcher.h" #include "ash/app_list/views/search_box_view.h" #include "ash/app_list/views/suggestion_chip_container_view.h" -#include "ash/app_list/views/suggestions_container_view.h" #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_switches.h" #include "base/command_line.h"
diff --git a/ash/app_list/views/apps_grid_view.cc b/ash/app_list/views/apps_grid_view.cc index 22434b31..b78fce7 100644 --- a/ash/app_list/views/apps_grid_view.cc +++ b/ash/app_list/views/apps_grid_view.cc
@@ -51,6 +51,7 @@ #include "ui/gfx/geometry/vector2d_conversions.h" #include "ui/gfx/skia_paint_util.h" #include "ui/strings/grit/ui_strings.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/border.h" #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" @@ -385,6 +386,12 @@ void AppsGridView::DisableFocusForShowingActiveFolder(bool disabled) { for (int i = 0; i < view_model_.view_size(); ++i) view_model_.view_at(i)->SetEnabled(!disabled); + + // Ignore the grid view in accessibility tree so that items inside it will not + // be accessed by ChromeVox. + GetViewAccessibility().OverrideIsIgnored(disabled); + GetViewAccessibility().NotifyAccessibilityEvent( + ax::mojom::Event::kTreeChanged); } void AppsGridView::OnTabletModeChanged(bool started) {
diff --git a/ash/app_list/views/apps_grid_view_unittest.cc b/ash/app_list/views/apps_grid_view_unittest.cc index 428cb04..b165914d 100644 --- a/ash/app_list/views/apps_grid_view_unittest.cc +++ b/ash/app_list/views/apps_grid_view_unittest.cc
@@ -28,7 +28,6 @@ #include "ash/app_list/views/search_box_view.h" #include "ash/app_list/views/search_result_tile_item_view.h" #include "ash/app_list/views/suggestion_chip_container_view.h" -#include "ash/app_list/views/suggestions_container_view.h" #include "ash/app_list/views/test/apps_grid_view_test_api.h" #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_constants.h"
diff --git a/ash/app_list/views/search_result_tile_item_view.cc b/ash/app_list/views/search_result_tile_item_view.cc index 5496994..ed2479bb 100644 --- a/ash/app_list/views/search_result_tile_item_view.cc +++ b/ash/app_list/views/search_result_tile_item_view.cc
@@ -102,6 +102,7 @@ title_->SetLineHeight(kTileTextLineHeight); title_->SetHorizontalAlignment(gfx::ALIGN_CENTER); title_->SetHandlesTooltips(false); + title_->SetAllowCharacterBreak(true); AddChildView(title_); if (is_play_store_app_search_enabled_) {
diff --git a/ash/app_list/views/suggestion_chip_container_view.cc b/ash/app_list/views/suggestion_chip_container_view.cc index 98fcfd6b..371e8d1b 100644 --- a/ash/app_list/views/suggestion_chip_container_view.cc +++ b/ash/app_list/views/suggestion_chip_container_view.cc
@@ -14,6 +14,7 @@ #include "ash/public/cpp/app_list/app_list_config.h" #include "ash/public/cpp/app_list/app_list_constants.h" #include "ash/public/cpp/app_list/app_list_features.h" +#include "ui/views/accessibility/view_accessibility.h" #include "ui/views/controls/textfield/textfield.h" #include "ui/views/focus/focus_manager.h" #include "ui/views/layout/box_layout.h" @@ -128,6 +129,12 @@ bool disabled) { for (auto* chip : suggestion_chip_views_) chip->suggestion_chip_view()->SetEnabled(!disabled); + + // Ignore the container view in accessibility tree so that suggestion chips + // will not be accessed by ChromeVox. + GetViewAccessibility().OverrideIsIgnored(disabled); + GetViewAccessibility().NotifyAccessibilityEvent( + ax::mojom::Event::kTreeChanged); } void SuggestionChipContainerView::OnTabletModeChanged(bool started) {
diff --git a/ash/app_list/views/suggestions_container_view.cc b/ash/app_list/views/suggestions_container_view.cc deleted file mode 100644 index c0187cf..0000000 --- a/ash/app_list/views/suggestions_container_view.cc +++ /dev/null
@@ -1,122 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "ash/app_list/views/suggestions_container_view.h" - -#include <memory> - -#include "ash/app_list/views/app_list_main_view.h" -#include "ash/app_list/views/contents_view.h" -#include "ash/app_list/views/search_result_tile_item_view.h" -#include "ash/public/cpp/app_list/app_list_config.h" -#include "ash/public/cpp/app_list/app_list_constants.h" -#include "ash/public/cpp/app_list/app_list_features.h" -#include "ui/views/background.h" -#include "ui/views/layout/grid_layout.h" - -namespace app_list { - -SuggestionsContainerView::SuggestionsContainerView( - ContentsView* contents_view, - PaginationModel* pagination_model) - : contents_view_(contents_view), pagination_model_(pagination_model) { - SetPaintToLayer(); - layer()->SetFillsBoundsOpaquely(false); - - DCHECK(contents_view); - view_delegate_ = contents_view_->GetAppListMainView()->view_delegate(); - SetBackground(views::CreateSolidBackground(kLabelBackgroundColor)); - - CreateAppsGrid(kNumStartPageTiles); -} - -SuggestionsContainerView::~SuggestionsContainerView() = default; - -int SuggestionsContainerView::DoUpdate() { - // Ignore updates and disable buttons when suggestions container view is not - // shown. - const ash::AppListState state = contents_view_->GetActiveState(); - if (state != ash::AppListState::kStateStart && - state != ash::AppListState::kStateApps) { - for (auto* view : search_result_tile_views_) - view->SetEnabled(false); - - return num_results(); - } - - std::vector<SearchResult*> display_results = - SearchModel::FilterSearchResultsByDisplayType( - results(), ash::SearchResultDisplayType::kRecommendation, - /*excludes=*/{}, kNumStartPageTiles); - if (display_results.size() != search_result_tile_views_.size()) { - // We should recreate the grid layout in this case. - for (size_t i = 0; i < search_result_tile_views_.size(); ++i) - delete search_result_tile_views_[i]; - search_result_tile_views_.clear(); - - CreateAppsGrid(display_results.size()); - } - - // Update the tile item results. - for (size_t i = 0; i < search_result_tile_views_.size(); ++i) { - DCHECK(i < display_results.size()); - search_result_tile_views_[i]->SetSearchResult(display_results[i]); - search_result_tile_views_[i]->SetEnabled(true); - - // Notify text change after accessible name is updated and the tile view - // is re-enabled, so that ChromeVox will announce the updated text. - search_result_tile_views_[i]->NotifyAccessibilityEvent( - ax::mojom::Event::kTextChanged, true); - } - - parent()->Layout(); - return display_results.size(); -} - -void SuggestionsContainerView::NotifyFirstResultYIndex(int /*y_index*/) { - NOTREACHED(); -} - -int SuggestionsContainerView::GetYSize() { - NOTREACHED(); - return 0; -} - -SearchResultBaseView* SuggestionsContainerView::GetFirstResultView() { - return nullptr; -} - -const char* SuggestionsContainerView::GetClassName() const { - return "SuggestionsContainerView"; -} - -void SuggestionsContainerView::CreateAppsGrid(int apps_num) { - DCHECK(search_result_tile_views_.empty()); - views::GridLayout* tiles_layout_manager = - SetLayoutManager(std::make_unique<views::GridLayout>(this)); - - views::ColumnSet* column_set = tiles_layout_manager->AddColumnSet(0); - for (int col = 0; col < kNumStartPageTiles; ++col) { - column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 0, - views::GridLayout::USE_PREF, 0, 0); - column_set->AddPaddingColumn(0, - AppListConfig::instance().grid_tile_spacing()); - } - - // Add SearchResultTileItemViews to the container. - int i = 0; - search_result_tile_views_.reserve(apps_num); - tiles_layout_manager->StartRow(0, 0); - DCHECK_LE(apps_num, kNumStartPageTiles); - for (; i < apps_num; ++i) { - SearchResultTileItemView* tile_item = new SearchResultTileItemView( - view_delegate_, pagination_model_, true /* show_in_apps_page */); - tiles_layout_manager->AddView(tile_item); - AddChildView(tile_item); - tile_item->SetParentBackgroundColor(kLabelBackgroundColor); - search_result_tile_views_.emplace_back(tile_item); - } -} - -} // namespace app_list
diff --git a/ash/app_list/views/suggestions_container_view.h b/ash/app_list/views/suggestions_container_view.h deleted file mode 100644 index 2da5e24..0000000 --- a/ash/app_list/views/suggestions_container_view.h +++ /dev/null
@@ -1,54 +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 ASH_APP_LIST_VIEWS_SUGGESTIONS_CONTAINER_VIEW_H_ -#define ASH_APP_LIST_VIEWS_SUGGESTIONS_CONTAINER_VIEW_H_ - -#include <vector> - -#include "ash/app_list/views/search_result_container_view.h" -#include "base/macros.h" - -namespace app_list { - -class AppListViewDelegate; -class ContentsView; -class PaginationModel; -class SearchResultTileItemView; - -// A container that holds the suggested app tiles. If fullscreen app list is not -// enabled, it also holds the all apps button. -class SuggestionsContainerView : public SearchResultContainerView { - public: - SuggestionsContainerView(ContentsView* contents_view, - PaginationModel* pagination_model); - ~SuggestionsContainerView() override; - - const std::vector<SearchResultTileItemView*>& tile_views() const { - return search_result_tile_views_; - } - - // Overridden from SearchResultContainerView: - int DoUpdate() override; - void NotifyFirstResultYIndex(int y_index) override; - int GetYSize() override; - SearchResultBaseView* GetFirstResultView() override; - const char* GetClassName() const override; - - private: - void CreateAppsGrid(int apps_num); - - ContentsView* contents_view_ = nullptr; - AppListViewDelegate* view_delegate_ = nullptr; - - std::vector<SearchResultTileItemView*> search_result_tile_views_; - - PaginationModel* const pagination_model_; // Owned by AppsGridView. - - DISALLOW_COPY_AND_ASSIGN(SuggestionsContainerView); -}; - -} // namespace app_list - -#endif // ASH_APP_LIST_VIEWS_SUGGESTIONS_CONTAINER_VIEW_H_
diff --git a/ash/events/switch_access_event_handler.cc b/ash/events/switch_access_event_handler.cc index 2102618..121c92c 100644 --- a/ash/events/switch_access_event_handler.cc +++ b/ash/events/switch_access_event_handler.cc
@@ -27,7 +27,7 @@ SwitchAccessEventHandler::SwitchAccessEventHandler( mojom::SwitchAccessEventHandlerDelegatePtr delegate_ptr) - : delegate_ptr_(std::move(delegate_ptr)), ignore_virtual_key_events_(true) { + : delegate_ptr_(std::move(delegate_ptr)) { DCHECK(delegate_ptr_.is_bound()); Shell::Get()->AddPreTargetHandler(this, ui::EventTarget::Priority::kAccessibility); @@ -45,15 +45,22 @@ DCHECK(IsSwitchAccessEnabled()); DCHECK(event); - // Ignore virtual key events so users can type with the onscreen keyboard. - if (ignore_virtual_key_events_ && !event->HasNativeEvent()) - return; - - ui::KeyboardCode key_code = event->key_code(); - if (keys_to_capture_.find(key_code) != keys_to_capture_.end()) { + if (ShouldForwardEvent(*event)) { CancelEvent(event); delegate_ptr_->DispatchKeyEvent(ui::Event::Clone(*event)); } } +bool SwitchAccessEventHandler::ShouldForwardEvent( + const ui::KeyEvent& event) const { + // Ignore virtual key events so users can type with the onscreen keyboard. + if (ignore_virtual_key_events_ && !event.HasNativeEvent()) + return false; + + if (forward_key_events_) + return true; + + return keys_to_capture_.find(event.key_code()) != keys_to_capture_.end(); +} + } // namespace ash
diff --git a/ash/events/switch_access_event_handler.h b/ash/events/switch_access_event_handler.h index bed2b40..035473f 100644 --- a/ash/events/switch_access_event_handler.h +++ b/ash/events/switch_access_event_handler.h
@@ -30,6 +30,12 @@ ignore_virtual_key_events_ = should_ignore; } + // Tells the handler whether to forward all incoming key events to the Switch + // Access extension. + void set_forward_key_events(bool should_forward) { + forward_key_events_ = should_forward; + } + // For testing usage only. void FlushMojoForTest(); @@ -37,11 +43,14 @@ // ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; + bool ShouldForwardEvent(const ui::KeyEvent& event) const; + // The delegate used to send key events to the Switch Access extension. mojom::SwitchAccessEventHandlerDelegatePtr delegate_ptr_; std::set<int> keys_to_capture_; - bool ignore_virtual_key_events_; + bool forward_key_events_ = false; + bool ignore_virtual_key_events_ = true; DISALLOW_COPY_AND_ASSIGN(SwitchAccessEventHandler); };
diff --git a/ash/events/switch_access_event_handler_unittest.cc b/ash/events/switch_access_event_handler_unittest.cc index 2d48bfb6..1788a35 100644 --- a/ash/events/switch_access_event_handler_unittest.cc +++ b/ash/events/switch_access_event_handler_unittest.cc
@@ -205,5 +205,43 @@ EXPECT_FALSE(event_capturer_.last_key_event()->handled()); } +TEST_F(SwitchAccessEventHandlerTest, ForwardKeyEvents) { + Shell::Get()->accessibility_controller()->SetSwitchAccessKeysToCapture( + {ui::VKEY_1, ui::VKEY_2, ui::VKEY_3}); + + EXPECT_FALSE(event_capturer_.last_key_event()); + + // Tell the Switch Access Event Handler to forward key events. + Shell::Get()->accessibility_controller()->ForwardKeyEventsToSwitchAccess( + true); + + // Press the "T" key. + generator_->PressKey(ui::VKEY_T, ui::EF_NONE); + + // The event should be handled by SwitchAccessEventHandler. + EXPECT_FALSE(event_capturer_.last_key_event()); + EXPECT_TRUE(GetDelegate()->last_key_event()); + + // Release the "T" key. + generator_->ReleaseKey(ui::VKEY_T, ui::EF_NONE); + + // The event should be handled by SwitchAccessEventHandler. + EXPECT_FALSE(event_capturer_.last_key_event()); + EXPECT_TRUE(GetDelegate()->last_key_event()); + + // Tell the Switch Access Event Handler to stop forwarding key events. + Shell::Get()->accessibility_controller()->ForwardKeyEventsToSwitchAccess( + false); + + // Press the "T" key. + generator_->PressKey(ui::VKEY_T, ui::EF_NONE); + + // The release event is not handled by SwitchAccessEventHandler. + EXPECT_TRUE(event_capturer_.last_key_event()); + + // Release the "T" key. + generator_->ReleaseKey(ui::VKEY_T, ui::EF_NONE); +} + } // namespace } // namespace ash
diff --git a/ash/public/interfaces/accessibility_controller.mojom b/ash/public/interfaces/accessibility_controller.mojom index b969db7..c26e1eed 100644 --- a/ash/public/interfaces/accessibility_controller.mojom +++ b/ash/public/interfaces/accessibility_controller.mojom
@@ -169,6 +169,10 @@ // Starts or stops dictation. Records metrics for toggling via SwitchAccess. ToggleDictationFromSource(DictationToggleSource source); + + // Tells the Switch Access Event Handler whether to forward all key events to + // the Switch Access extension. + ForwardKeyEventsToSwitchAccess(bool should_forward); }; // Interface for ash to request accessibility service from its client (e.g.
diff --git a/base/android/jni_generator/golden/testInnerClassNativesBothInnerAndOuterRegistrations.golden b/base/android/jni_generator/golden/testInnerClassNativesBothInnerAndOuterRegistrations.golden index 04d7680..0034740 100644 --- a/base/android/jni_generator/golden/testInnerClassNativesBothInnerAndOuterRegistrations.golden +++ b/base/android/jni_generator/golden/testInnerClassNativesBothInnerAndOuterRegistrations.golden
@@ -14,6 +14,7 @@ #include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_int_wrapper.h" +#include "base/stl_util.h" // For base::size(). // Step 1: Forward declarations (classes). @@ -64,7 +65,7 @@ JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { const int kMethods_org_chromium_TestJniSize = - arraysize(kMethods_org_chromium_TestJni); + base::size(kMethods_org_chromium_TestJni); if (env->RegisterNatives( org_chromium_TestJni_clazz(env), kMethods_org_chromium_TestJni, @@ -77,7 +78,7 @@ const int kMethods_org_chromium_TestJni_00024MyOtherInnerClassSize = - arraysize(kMethods_org_chromium_TestJni_00024MyOtherInnerClass); + base::size(kMethods_org_chromium_TestJni_00024MyOtherInnerClass); if (env->RegisterNatives( org_chromium_TestJni_00024MyOtherInnerClass_clazz(env), kMethods_org_chromium_TestJni_00024MyOtherInnerClass,
diff --git a/base/android/jni_generator/golden/testNativesRegistrations.golden b/base/android/jni_generator/golden/testNativesRegistrations.golden index b3b99745..3f1d8e2 100644 --- a/base/android/jni_generator/golden/testNativesRegistrations.golden +++ b/base/android/jni_generator/golden/testNativesRegistrations.golden
@@ -14,6 +14,7 @@ #include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_int_wrapper.h" +#include "base/stl_util.h" // For base::size(). // Step 1: Forward declarations (classes). @@ -143,7 +144,7 @@ JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_TestJni(JNIEnv* env) { const int kMethods_org_chromium_TestJniSize = - arraysize(kMethods_org_chromium_TestJni); + base::size(kMethods_org_chromium_TestJni); if (env->RegisterNatives( org_chromium_TestJni_clazz(env), kMethods_org_chromium_TestJni,
diff --git a/base/android/jni_generator/golden/testProxyNativesMainDex.golden b/base/android/jni_generator/golden/testProxyNativesMainDex.golden index f093270..eaa03c2 100644 --- a/base/android/jni_generator/golden/testProxyNativesMainDex.golden +++ b/base/android/jni_generator/golden/testProxyNativesMainDex.golden
@@ -14,6 +14,7 @@ #include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_int_wrapper.h" +#include "base/stl_util.h" // For base::size(). // Step 1: Forward declarations (classes). @@ -37,7 +38,7 @@ }; JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNIMAIN_DEX(JNIEnv* env) { - const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX); + const int number_of_methods = base::size(kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX); base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI"); if (env->RegisterNatives(
diff --git a/base/android/jni_generator/golden/testProxyNativesMainDexAndNonMainDex.golden b/base/android/jni_generator/golden/testProxyNativesMainDexAndNonMainDex.golden index 6b909a7..e917fc9 100644 --- a/base/android/jni_generator/golden/testProxyNativesMainDexAndNonMainDex.golden +++ b/base/android/jni_generator/golden/testProxyNativesMainDexAndNonMainDex.golden
@@ -14,6 +14,7 @@ #include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_int_wrapper.h" +#include "base/stl_util.h" // For base::size(). // Step 1: Forward declarations (classes). @@ -44,7 +45,7 @@ }; JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNI(JNIEnv* env) { - const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNI); + const int number_of_methods = base::size(kMethods_org_chromium_base_natives_GEN_1JNI); base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI"); if (env->RegisterNatives( @@ -67,7 +68,7 @@ }; JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNIMAIN_DEX(JNIEnv* env) { - const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX); + const int number_of_methods = base::size(kMethods_org_chromium_base_natives_GEN_1JNIMAIN_DEX); base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI"); if (env->RegisterNatives(
diff --git a/base/android/jni_generator/golden/testProxyNativesRegistrations.golden b/base/android/jni_generator/golden/testProxyNativesRegistrations.golden index 13b5cc2..d43101b 100644 --- a/base/android/jni_generator/golden/testProxyNativesRegistrations.golden +++ b/base/android/jni_generator/golden/testProxyNativesRegistrations.golden
@@ -14,6 +14,7 @@ #include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_int_wrapper.h" +#include "base/stl_util.h" // For base::size(). // Step 1: Forward declarations (classes). @@ -57,7 +58,7 @@ }; JNI_REGISTRATION_EXPORT bool RegisterNative_org_chromium_base_natives_GEN_1JNI(JNIEnv* env) { - const int number_of_methods = arraysize(kMethods_org_chromium_base_natives_GEN_1JNI); + const int number_of_methods = base::size(kMethods_org_chromium_base_natives_GEN_1JNI); base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "org/chromium/base/natives/GEN_JNI"); if (env->RegisterNatives(
diff --git a/base/android/jni_generator/jni_registration_generator.py b/base/android/jni_generator/jni_registration_generator.py index 1499baf..1a6ae3b 100755 --- a/base/android/jni_generator/jni_registration_generator.py +++ b/base/android/jni_generator/jni_registration_generator.py
@@ -124,7 +124,7 @@ }; JNI_REGISTRATION_EXPORT bool ${REGISTRATION_NAME}(JNIEnv* env) { - const int number_of_methods = arraysize(kMethods_${ESCAPED_PROXY_CLASS}); + const int number_of_methods = base::size(kMethods_${ESCAPED_PROXY_CLASS}); base::android::ScopedJavaLocalRef<jclass> native_clazz = base::android::GetClass(env, "${PROXY_CLASS}"); if (env->RegisterNatives( @@ -238,6 +238,7 @@ #include "base/android/jni_generator/jni_generator_helper.h" #include "base/android/jni_int_wrapper.h" +#include "base/stl_util.h" // For base::size(). // Step 1: Forward declarations (classes). @@ -482,7 +483,7 @@ """Returns the shared implementation for RegisterNatives.""" template = string.Template("""\ const int kMethods_${JAVA_CLASS}Size = - arraysize(${NAMESPACE}kMethods_${JAVA_CLASS}); + base::size(${NAMESPACE}kMethods_${JAVA_CLASS}); if (env->RegisterNatives( ${JAVA_CLASS}_clazz(env), ${NAMESPACE}kMethods_${JAVA_CLASS},
diff --git a/base/task/sequence_manager/task_queue_impl.cc b/base/task/sequence_manager/task_queue_impl.cc index b81c261..f0031c3 100644 --- a/base/task/sequence_manager/task_queue_impl.cc +++ b/base/task/sequence_manager/task_queue_impl.cc
@@ -89,6 +89,7 @@ immediate_work_queue(new WorkQueue(task_queue, "immediate", WorkQueue::QueueType::kImmediate)), + set_index(0), is_enabled_refcount(0), voter_refcount(0), blame_context(nullptr),
diff --git a/base/task/sequence_manager/task_queue_impl.h b/base/task/sequence_manager/task_queue_impl.h index 873fec0..90dcac1 100644 --- a/base/task/sequence_manager/task_queue_impl.h +++ b/base/task/sequence_manager/task_queue_impl.h
@@ -322,6 +322,7 @@ std::unique_ptr<WorkQueue> immediate_work_queue; DelayedIncomingQueue delayed_incoming_queue; ObserverList<MessageLoop::TaskObserver>::Unchecked task_observers; + size_t set_index; base::internal::HeapHandle heap_handle; int is_enabled_refcount; int voter_refcount;
diff --git a/base/task/sequence_manager/task_queue_selector.cc b/base/task/sequence_manager/task_queue_selector.cc index 6583cdd..5f301b0 100644 --- a/base/task/sequence_manager/task_queue_selector.cc +++ b/base/task/sequence_manager/task_queue_selector.cc
@@ -17,13 +17,11 @@ namespace sequence_manager { namespace internal { -constexpr const int64_t TaskQueueSelector::per_priority_starvation_tolerance_[]; - TaskQueueSelector::TaskQueueSelector( scoped_refptr<AssociatedThreadId> associated_thread) : associated_thread_(std::move(associated_thread)), - delayed_work_queue_sets_("delayed", this), - immediate_work_queue_sets_("immediate", this) {} + delayed_work_queue_sets_("delayed"), + immediate_work_queue_sets_("immediate") {} TaskQueueSelector::~TaskQueueSelector() = default; @@ -113,39 +111,6 @@ #endif } -int64_t TaskQueueSelector::GetSortKeyForPriorty(size_t set_index) const { - switch (set_index) { - case TaskQueue::kControlPriority: - return std::numeric_limits<int64_t>::min(); - - case TaskQueue::kBestEffortPriority: - return std::numeric_limits<int64_t>::max(); - - default: - return selection_count_ + per_priority_starvation_tolerance_[set_index]; - } -} - -void TaskQueueSelector::WorkQueueSetBecameEmpty(size_t set_index) { - non_empty_set_counts_[set_index]--; - DCHECK_GE(non_empty_set_counts_[set_index], 0); - - // There are no delayed or immediate tasks for |set_index| so remove from - // |active_priorities_|. - if (non_empty_set_counts_[set_index] == 0) - active_priorities_.erase(set_index); -} - -void TaskQueueSelector::WorkQueueSetBecameNonEmpty(size_t set_index) { - non_empty_set_counts_[set_index]++; - DCHECK_LE(non_empty_set_counts_[set_index], 2); - - // There is now a delayed or an immediate task for |set_index|, so add to - // |active_priorities_|. - if (non_empty_set_counts_[set_index] == 1) - active_priorities_.insert(GetSortKeyForPriorty(set_index), set_index); -} - WorkQueue* TaskQueueSelector::ChooseOldestImmediateTaskWithPriority( TaskQueue::QueuePriority priority) const { return immediate_work_queue_sets_.GetOldestQueueInSet(priority); @@ -196,6 +161,58 @@ priority, out_chose_delayed_over_immediate); } +WorkQueue* TaskQueueSelector::SelectWorkQueueToServiceImpl( + TaskQueue::QueuePriority max_priority, + bool* out_chose_delayed_over_immediate) { + DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); + DCHECK_EQ(*out_chose_delayed_over_immediate, false); + + // Always service the control queue if it has any work. + if (max_priority > TaskQueue::kControlPriority) { + WorkQueue* queue = ChooseOldestWithPriority( + TaskQueue::kControlPriority, out_chose_delayed_over_immediate); + if (queue) + return queue; + } + + // Select from the low priority queue if we are starving it. + if (max_priority > TaskQueue::kLowPriority && + low_priority_starvation_score_ >= kMaxLowPriorityStarvationScore) { + WorkQueue* queue = ChooseOldestWithPriority( + TaskQueue::kLowPriority, out_chose_delayed_over_immediate); + if (queue) + return queue; + } + + // Select from the normal priority queue if we are starving it. + if (max_priority > TaskQueue::kNormalPriority && + normal_priority_starvation_score_ >= kMaxNormalPriorityStarvationScore) { + WorkQueue* queue = ChooseOldestWithPriority( + TaskQueue::kNormalPriority, out_chose_delayed_over_immediate); + if (queue) + return queue; + } + + // Select from the high priority queue if we are starving it. + if (max_priority > TaskQueue::kHighPriority && + high_priority_starvation_score_ >= kMaxHighPriorityStarvationScore) { + WorkQueue* queue = ChooseOldestWithPriority( + TaskQueue::kHighPriority, out_chose_delayed_over_immediate); + if (queue) + return queue; + } + + // Otherwise choose in priority order. + for (TaskQueue::QueuePriority priority = TaskQueue::kHighestPriority; + priority < max_priority; priority = NextPriority(priority)) { + WorkQueue* queue = + ChooseOldestWithPriority(priority, out_chose_delayed_over_immediate); + if (queue) + return queue; + } + return nullptr; +} + #if DCHECK_IS_ON() || !defined(NDEBUG) bool TaskQueueSelector::CheckContainsQueueForTest( const internal::TaskQueueImpl* queue) const { @@ -214,36 +231,81 @@ WorkQueue* TaskQueueSelector::SelectWorkQueueToService() { DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); - - if (active_priorities_.empty()) - return nullptr; - - selection_count_++; - - // Select the priority from which we will select a task. Usually this is - // the highest priority for which we have work, unless we are starving a lower - // priority. - size_t set_index = active_priorities_.min_id(); bool chose_delayed_over_immediate = false; - WorkQueue* queue = - ChooseOldestWithPriority(static_cast<TaskQueue::QueuePriority>(set_index), - &chose_delayed_over_immediate); + WorkQueue* queue = SelectWorkQueueToServiceImpl( + TaskQueue::kQueuePriorityCount, &chose_delayed_over_immediate); + if (queue) { + // We could use |(*out_work_queue)->task_queue()->GetQueuePriority()| here + // but for re-queued non-nestable tasks |task_queue()| returns null. + DidSelectQueueWithPriority( + static_cast<TaskQueue::QueuePriority>(queue->work_queue_set_index()), + chose_delayed_over_immediate); + } + return queue; +} - // If we still have any tasks remaining for |set_index| then adjust it's - // sort key. - if (active_priorities_.IsInQueue(set_index)) - active_priorities_.ChangeMinKey(GetSortKeyForPriorty(set_index)); - +void TaskQueueSelector::DidSelectQueueWithPriority( + TaskQueue::QueuePriority priority, + bool chose_delayed_over_immediate) { + switch (priority) { + case TaskQueue::kControlPriority: + break; + case TaskQueue::kHighestPriority: + low_priority_starvation_score_ += + HasTasksWithPriority(TaskQueue::kLowPriority) + ? kSmallScoreIncrementForLowPriorityStarvation + : 0; + normal_priority_starvation_score_ += + HasTasksWithPriority(TaskQueue::kNormalPriority) + ? kSmallScoreIncrementForNormalPriorityStarvation + : 0; + high_priority_starvation_score_ += + HasTasksWithPriority(TaskQueue::kHighPriority) + ? kSmallScoreIncrementForHighPriorityStarvation + : 0; + break; + case TaskQueue::kHighPriority: + low_priority_starvation_score_ += + HasTasksWithPriority(TaskQueue::kLowPriority) + ? kLargeScoreIncrementForLowPriorityStarvation + : 0; + normal_priority_starvation_score_ += + HasTasksWithPriority(TaskQueue::kNormalPriority) + ? kLargeScoreIncrementForNormalPriorityStarvation + : 0; + high_priority_starvation_score_ = 0; + break; + case TaskQueue::kNormalPriority: + low_priority_starvation_score_ += + HasTasksWithPriority(TaskQueue::kLowPriority) + ? kLargeScoreIncrementForLowPriorityStarvation + : 0; + normal_priority_starvation_score_ = 0; + break; + case TaskQueue::kLowPriority: + case TaskQueue::kBestEffortPriority: + low_priority_starvation_score_ = 0; + high_priority_starvation_score_ = 0; + normal_priority_starvation_score_ = 0; + break; + default: + NOTREACHED(); + } if (chose_delayed_over_immediate) { immediate_starvation_count_++; } else { immediate_starvation_count_ = 0; } - return queue; } void TaskQueueSelector::AsValueInto(trace_event::TracedValue* state) const { DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); + state->SetInteger("high_priority_starvation_score", + high_priority_starvation_score_); + state->SetInteger("normal_priority_starvation_score", + normal_priority_starvation_score_); + state->SetInteger("low_priority_starvation_score", + low_priority_starvation_score_); state->SetInteger("immediate_starvation_count", immediate_starvation_count_); } @@ -253,7 +315,15 @@ bool TaskQueueSelector::AllEnabledWorkQueuesAreEmpty() const { DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker); - return active_priorities_.empty(); + for (TaskQueue::QueuePriority priority = TaskQueue::kControlPriority; + priority < TaskQueue::kQueuePriorityCount; + priority = NextPriority(priority)) { + if (!delayed_work_queue_sets_.IsSetEmpty(priority) || + !immediate_work_queue_sets_.IsSetEmpty(priority)) { + return false; + } + } + return true; } void TaskQueueSelector::SetImmediateStarvationCountForTest( @@ -267,62 +337,6 @@ !immediate_work_queue_sets_.IsSetEmpty(priority); } -TaskQueueSelector::SmallPriorityQueue::SmallPriorityQueue() { - for (size_t i = 0; i < TaskQueue::kQueuePriorityCount; i++) { - id_to_index_[i] = kInvalidIndex; - } -} - -void TaskQueueSelector::SmallPriorityQueue::insert(int64_t key, uint8_t id) { - DCHECK_LE(size_, TaskQueue::kQueuePriorityCount); - DCHECK_LT(id, TaskQueue::kQueuePriorityCount); - DCHECK(!IsInQueue(id)); - // Insert while keeping |keys_| sorted. - size_t i = size_; - while (i > 0 && key < keys_[i - 1]) { - keys_[i] = keys_[i - 1]; - uint8_t moved_id = index_to_id_[i - 1]; - index_to_id_[i] = moved_id; - id_to_index_[moved_id] = i; - i--; - } - keys_[i] = key; - index_to_id_[i] = id; - id_to_index_[id] = i; - size_++; -} - -void TaskQueueSelector::SmallPriorityQueue::erase(uint8_t id) { - DCHECK_NE(size_, 0u); - DCHECK_LT(id, TaskQueue::kQueuePriorityCount); - DCHECK(IsInQueue(id)); - // Erase while keeping |keys_| sorted. - size_--; - for (size_t i = id_to_index_[id]; i < size_; i++) { - keys_[i] = keys_[i + 1]; - uint8_t moved_id = index_to_id_[i + 1]; - index_to_id_[i] = moved_id; - id_to_index_[moved_id] = i; - } - id_to_index_[id] = kInvalidIndex; -} - -void TaskQueueSelector::SmallPriorityQueue::ChangeMinKey(int64_t new_key) { - DCHECK_NE(size_, 0u); - uint8_t id = index_to_id_[0]; - size_t i = 0; - while ((i + 1) < size_ && keys_[i + 1] < new_key) { - keys_[i] = keys_[i + 1]; - uint8_t moved_id = index_to_id_[i + 1]; - index_to_id_[i] = moved_id; - id_to_index_[moved_id] = i; - i++; - } - keys_[i] = new_key; - index_to_id_[i] = id; - id_to_index_[id] = i; -} - } // namespace internal } // namespace sequence_manager } // namespace base
diff --git a/base/task/sequence_manager/task_queue_selector.h b/base/task/sequence_manager/task_queue_selector.h index b7ab2b6..153492f 100644 --- a/base/task/sequence_manager/task_queue_selector.h +++ b/base/task/sequence_manager/task_queue_selector.h
@@ -21,11 +21,11 @@ // TaskQueueSelector is used by the SchedulerHelper to enable prioritization // of particular task queues. -class BASE_EXPORT TaskQueueSelector : public WorkQueueSets::Observer { +class BASE_EXPORT TaskQueueSelector { public: explicit TaskQueueSelector( scoped_refptr<AssociatedThreadId> associated_thread); - ~TaskQueueSelector() override; + ~TaskQueueSelector(); // Called to register a queue that can be selected. This function is called // on the main thread. @@ -70,10 +70,6 @@ // otherwise. bool AllEnabledWorkQueuesAreEmpty() const; - // WorkQueueSets::Observer implementation: - void WorkQueueSetBecameEmpty(size_t set_index) override; - void WorkQueueSetBecameNonEmpty(size_t set_index) override; - protected: WorkQueue* ChooseOldestWithPriority( TaskQueue::QueuePriority priority, @@ -97,50 +93,48 @@ // the presence of highest priority tasks. static const size_t kMaxHighPriorityStarvationScore = 3; + // Increment to be applied to the high priority starvation score when a task + // should have only a small effect on the score. E.g. A number of highest + // priority tasks must run before the high priority queue is considered + // starved. + static const size_t kSmallScoreIncrementForHighPriorityStarvation = 1; + // Maximum score to accumulate before normal priority tasks are run even in // the presence of higher priority tasks i.e. highest and high priority tasks. static const size_t kMaxNormalPriorityStarvationScore = 5; + // Increment to be applied to the normal priority starvation score when a task + // should have a large effect on the score. E.g Only a few high priority + // priority tasks must run before the normal priority queue is considered + // starved. + static const size_t kLargeScoreIncrementForNormalPriorityStarvation = 2; + + // Increment to be applied to the normal priority starvation score when a task + // should have only a small effect on the score. E.g. A number of highest + // priority tasks must run before the normal priority queue is considered + // starved. + static const size_t kSmallScoreIncrementForNormalPriorityStarvation = 1; + // Maximum score to accumulate before low priority tasks are run even in the // presence of highest, high, or normal priority tasks. static const size_t kMaxLowPriorityStarvationScore = 25; + // Increment to be applied to the low priority starvation score when a task + // should have a large effect on the score. E.g. Only a few normal/high + // priority tasks must run before the low priority queue is considered + // starved. + static const size_t kLargeScoreIncrementForLowPriorityStarvation = 5; + + // Increment to be applied to the low priority starvation score when a task + // should have only a small effect on the score. E.g. A lot of highest + // priority tasks must run before the low priority queue is considered + // starved. + static const size_t kSmallScoreIncrementForLowPriorityStarvation = 1; + // Maximum number of delayed tasks tasks which can be run while there's a // waiting non-delayed task. static const size_t kMaxDelayedStarvationTasks = 3; - // Because there are only a handful of priorities, we can get away with using - // a very simple priority queue. This queue has a stable sorting order. - // Note IDs must be in the range [0..TaskQueue::kQueuePriorityCount) - class BASE_EXPORT SmallPriorityQueue { - public: - SmallPriorityQueue(); - - bool empty() const { return size_ == 0; } - - int min_id() const { return index_to_id_[0]; }; - - void insert(int64_t key, uint8_t id); - - void erase(uint8_t id); - - void ChangeMinKey(int64_t new_key); - - bool IsInQueue(uint8_t id) const { - return id_to_index_[id] != kInvalidIndex; - } - - private: - static constexpr uint8_t kInvalidIndex = 255; - - size_t size_ = 0; - - // These are sorted in ascending order. - int64_t keys_[TaskQueue::kQueuePriorityCount]; - uint8_t id_to_index_[TaskQueue::kQueuePriorityCount]; - uint8_t index_to_id_[TaskQueue::kQueuePriorityCount]; - }; - private: void ChangeSetIndex(internal::TaskQueueImpl* queue, TaskQueue::QueuePriority priority); @@ -148,6 +142,10 @@ TaskQueue::QueuePriority priority); void RemoveQueueImpl(internal::TaskQueueImpl* queue); + WorkQueue* SelectWorkQueueToServiceImpl( + TaskQueue::QueuePriority max_priority, + bool* out_chose_delayed_over_immediate); + #if DCHECK_IS_ON() || !defined(NDEBUG) bool CheckContainsQueueForTest(const internal::TaskQueueImpl* queue) const; #endif @@ -166,61 +164,22 @@ static TaskQueue::QueuePriority NextPriority( TaskQueue::QueuePriority priority); + // Called whenever the selector chooses a task queue for execution with the + // priority |priority|. + void DidSelectQueueWithPriority(TaskQueue::QueuePriority priority, + bool chose_delayed_over_immediate); + // Returns true if there are pending tasks with priority |priority|. bool HasTasksWithPriority(TaskQueue::QueuePriority priority); scoped_refptr<AssociatedThreadId> associated_thread_; - // Count of the number of sets (delayed or immediate) for each priority. - // Should only contain 0, 1 or 2. - std::array<int, TaskQueue::kQueuePriorityCount> non_empty_set_counts_ = {{0}}; - - // The Priority sort key is adjusted based on these values. The idea being the - // larger the adjustment, the more the queue can be starved before being - // selected. The kControlPriority queues should run immediately so it always - // has the lowest possible value. Conversely kBestEffortPriority queues should - // only run if there's nothing else to do so they always have the highest - // possible value. - static constexpr const int64_t - per_priority_starvation_tolerance_[TaskQueue::kQueuePriorityCount] = { - // kControlPriority (unused) - std::numeric_limits<int64_t>::min(), - - // kHighestPriority - 0, - - // kHighPriority - TaskQueueSelector::per_priority_starvation_tolerance_[1] + - kMaxHighPriorityStarvationScore, - - // kNormalPriority - TaskQueueSelector::per_priority_starvation_tolerance_[2] + - kMaxNormalPriorityStarvationScore, - - // kLowPriority - TaskQueueSelector::per_priority_starvation_tolerance_[3] + - kMaxLowPriorityStarvationScore, - - // kBestEffortPriority (unused) - std::numeric_limits<int64_t>::max()}; - - int64_t GetSortKeyForPriorty(size_t set_index) const; - - // Min priority queue of priorities, which is used to work out which priority - // to run next. - SmallPriorityQueue active_priorities_; - - // Each time we select a queue this is incremented. This forms the basis of - // the |active_priorities_| sort key. I.e. when a priority becomes selectable - // it's inserted into |active_priorities_| with a sort key of - // |selection_count_| plus an adjustment from - // |per_priority_starvation_tolerance_|. In theory this could wrap around and - // start misbehaving but in typical usage that would take a great many years. - int64_t selection_count_ = 0; - WorkQueueSets delayed_work_queue_sets_; WorkQueueSets immediate_work_queue_sets_; size_t immediate_starvation_count_ = 0; + size_t high_priority_starvation_score_ = 0; + size_t normal_priority_starvation_score_ = 0; + size_t low_priority_starvation_score_ = 0; Observer* task_queue_selector_observer_ = nullptr; // Not owned. DISALLOW_COPY_AND_ASSIGN(TaskQueueSelector);
diff --git a/base/task/sequence_manager/task_queue_selector_unittest.cc b/base/task/sequence_manager/task_queue_selector_unittest.cc index c1e634c..fa6d02c 100644 --- a/base/task/sequence_manager/task_queue_selector_unittest.cc +++ b/base/task/sequence_manager/task_queue_selector_unittest.cc
@@ -49,14 +49,50 @@ using TaskQueueSelector::ChooseOldestWithPriority; using TaskQueueSelector::delayed_work_queue_sets; using TaskQueueSelector::immediate_work_queue_sets; - using TaskQueueSelector::kMaxHighPriorityStarvationScore; - using TaskQueueSelector::kMaxLowPriorityStarvationScore; - using TaskQueueSelector::kMaxNormalPriorityStarvationScore; using TaskQueueSelector::SetImmediateStarvationCountForTest; - using TaskQueueSelector::SmallPriorityQueue; TaskQueueSelectorForTest(scoped_refptr<AssociatedThreadId> associated_thread) : TaskQueueSelector(associated_thread) {} + + // Returns the number of highest priority tasks needed to starve high priority + // task. + static constexpr size_t NumberOfHighestPriorityToStarveHighPriority() { + return (kMaxHighPriorityStarvationScore + + kSmallScoreIncrementForHighPriorityStarvation - 1) / + kSmallScoreIncrementForHighPriorityStarvation; + } + + // Returns the number of highest priority tasks needed to starve normal + // priority tasks. + static constexpr size_t NumberOfHighestPriorityToStarveNormalPriority() { + return (kMaxNormalPriorityStarvationScore + + kSmallScoreIncrementForNormalPriorityStarvation - 1) / + kSmallScoreIncrementForNormalPriorityStarvation; + } + + // Returns the number of high priority tasks needed to starve normal priority + // tasks. + static constexpr size_t NumberOfHighPriorityToStarveNormalPriority() { + return (kMaxNormalPriorityStarvationScore + + kLargeScoreIncrementForNormalPriorityStarvation - 1) / + kLargeScoreIncrementForNormalPriorityStarvation; + } + + // Returns the number of highest priority tasks needed to starve low priority + // ones. + static constexpr size_t NumberOfHighestPriorityToStarveLowPriority() { + return (kMaxLowPriorityStarvationScore + + kSmallScoreIncrementForLowPriorityStarvation - 1) / + kSmallScoreIncrementForLowPriorityStarvation; + } + + // Returns the number of high/normal priority tasks needed to starve low + // priority ones. + static constexpr size_t NumberOfHighAndNormalPriorityToStarveLowPriority() { + return (kMaxLowPriorityStarvationScore + + kLargeScoreIncrementForLowPriorityStarvation - 1) / + kLargeScoreIncrementForLowPriorityStarvation; + } }; class TaskQueueSelectorTest : public testing::Test { @@ -516,13 +552,12 @@ selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighestPriority); - constexpr const size_t kNumberOfHighestPriorityToStarveHighPriority = - TaskQueueSelectorForTest::kMaxHighPriorityStarvationScore; - // Run a number of highest priority tasks needed to starve high priority // tasks (when present). for (size_t num_tasks = 0; - num_tasks <= kNumberOfHighestPriorityToStarveHighPriority; num_tasks++) { + num_tasks <= + TaskQueueSelectorForTest::NumberOfHighestPriorityToStarveHighPriority(); + num_tasks++) { ASSERT_THAT(selector_.SelectWorkQueueToService(), NotNull()); // Don't remove task from queue to simulate the queue is still full. } @@ -549,14 +584,11 @@ selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighestPriority); - constexpr const size_t kNumberOfHighestPriorityToStarveNormalPriority = - TaskQueueSelectorForTest::kMaxHighPriorityStarvationScore + - TaskQueueSelectorForTest::kMaxNormalPriorityStarvationScore; - // Run a number of highest priority tasks needed to starve normal priority // tasks (when present). for (size_t num_tasks = 0; - num_tasks <= kNumberOfHighestPriorityToStarveNormalPriority; + num_tasks <= TaskQueueSelectorForTest:: + NumberOfHighestPriorityToStarveNormalPriority(); num_tasks++) { ASSERT_THAT(selector_.SelectWorkQueueToService(), NotNull()); // Don't remove task from queue to simulate the queue is still full. @@ -565,13 +597,12 @@ selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kHighPriority); selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighPriority); - constexpr const size_t kNumberOfHighPriorityToStarveNormalPriority = - TaskQueueSelectorForTest::kMaxNormalPriorityStarvationScore; - // Run a number of high priority tasks needed to starve normal priority // tasks (when present). for (size_t num_tasks = 0; - num_tasks <= kNumberOfHighPriorityToStarveNormalPriority; num_tasks++) { + num_tasks <= + TaskQueueSelectorForTest::NumberOfHighPriorityToStarveNormalPriority(); + num_tasks++) { ASSERT_THAT(selector_.SelectWorkQueueToService(), NotNull()); // Don't remove task from queue to simulate the queue is still full. } @@ -598,15 +629,12 @@ selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kHighestPriority); - constexpr const size_t kNumberOfHighestPriorityToStarveLowPriority = - TaskQueueSelectorForTest::kMaxHighPriorityStarvationScore + - TaskQueueSelectorForTest::kMaxNormalPriorityStarvationScore + - TaskQueueSelectorForTest::kMaxLowPriorityStarvationScore; - // Run a number of highest priority tasks needed to starve low priority // tasks (when present). for (size_t num_tasks = 0; - num_tasks <= kNumberOfHighestPriorityToStarveLowPriority; num_tasks++) { + num_tasks <= + TaskQueueSelectorForTest::NumberOfHighestPriorityToStarveLowPriority(); + num_tasks++) { ASSERT_THAT(selector_.SelectWorkQueueToService(), NotNull()); // Don't remove task from queue to simulate the queue is still full. } @@ -614,14 +642,11 @@ selector_.SetQueuePriority(task_queues_[0].get(), TaskQueue::kHighPriority); selector_.SetQueuePriority(task_queues_[1].get(), TaskQueue::kNormalPriority); - constexpr const size_t kNumberOfHighAndNormalPriorityToStarveLowPriority = - TaskQueueSelectorForTest::kMaxNormalPriorityStarvationScore + - TaskQueueSelectorForTest::kMaxLowPriorityStarvationScore; - // Run a number of high/normal priority tasks needed to starve low priority // tasks (when present). for (size_t num_tasks = 0; - num_tasks <= kNumberOfHighAndNormalPriorityToStarveLowPriority; + num_tasks <= TaskQueueSelectorForTest:: + NumberOfHighAndNormalPriorityToStarveLowPriority(); num_tasks++) { ASSERT_THAT(selector_.SelectWorkQueueToService(), NotNull()); // Don't remove task from queue to simulate the queue is still full. @@ -808,169 +833,6 @@ ChooseOldestWithPriorityTest, testing::ValuesIn(kChooseOldestWithPriorityTestCases)); -class SmallPriorityQueueTest : public testing::Test { - public: - TaskQueueSelectorForTest::SmallPriorityQueue queue_; - - std::vector<uint8_t> PopAllIds() { - std::vector<uint8_t> result; - while (!queue_.empty()) { - result.push_back(queue_.min_id()); - queue_.erase(queue_.min_id()); - } - return result; - } -}; - -TEST_F(SmallPriorityQueueTest, Insert) { - EXPECT_TRUE(queue_.empty()); - - EXPECT_FALSE(queue_.IsInQueue(1)); - queue_.insert(1000, 1); - EXPECT_TRUE(queue_.IsInQueue(1)); - EXPECT_EQ(1, queue_.min_id()); - EXPECT_FALSE(queue_.empty()); - - EXPECT_FALSE(queue_.IsInQueue(2)); - queue_.insert(1002, 2); - EXPECT_TRUE(queue_.IsInQueue(2)); - EXPECT_EQ(1, queue_.min_id()); - - EXPECT_FALSE(queue_.IsInQueue(3)); - queue_.insert(999, 3); - EXPECT_TRUE(queue_.IsInQueue(3)); - EXPECT_EQ(3, queue_.min_id()); - - EXPECT_FALSE(queue_.IsInQueue(4)); - queue_.insert(1003, 4); - EXPECT_TRUE(queue_.IsInQueue(4)); - EXPECT_EQ(3, queue_.min_id()); -} - -TEST_F(SmallPriorityQueueTest, EraseMin) { - queue_.insert(1000, 1); - queue_.insert(1002, 2); - queue_.insert(999, 3); - queue_.insert(1003, 4); - - EXPECT_EQ(3, queue_.min_id()); - EXPECT_TRUE(queue_.IsInQueue(4)); - - queue_.erase(4); - EXPECT_FALSE(queue_.IsInQueue(4)); - EXPECT_EQ(3, queue_.min_id()); - EXPECT_TRUE(queue_.IsInQueue(3)); - - queue_.erase(3); - EXPECT_FALSE(queue_.IsInQueue(3)); - EXPECT_EQ(1, queue_.min_id()); - EXPECT_TRUE(queue_.IsInQueue(2)); - - queue_.erase(2); - EXPECT_FALSE(queue_.IsInQueue(2)); - EXPECT_EQ(1, queue_.min_id()); - EXPECT_TRUE(queue_.IsInQueue(1)); - - queue_.erase(1); - EXPECT_FALSE(queue_.IsInQueue(1)); - EXPECT_TRUE(queue_.empty()); -} - -TEST_F(SmallPriorityQueueTest, EraseMiddle) { - queue_.insert(100, 1); - queue_.insert(101, 2); - queue_.insert(102, 3); - queue_.insert(103, 4); - queue_.insert(104, 5); - - queue_.erase(3); - - EXPECT_THAT(PopAllIds(), ElementsAre(1, 2, 4, 5)); -} - -TEST_F(SmallPriorityQueueTest, EraseAllButOne) { - queue_.insert(100, 1); - queue_.insert(101, 2); - queue_.insert(102, 3); - queue_.insert(103, 4); - queue_.insert(104, 5); - - queue_.erase(5); - queue_.erase(1); - queue_.erase(3); - queue_.erase(2); - - EXPECT_THAT(PopAllIds(), ElementsAre(4)); -} - -TEST_F(SmallPriorityQueueTest, ChangeMinKeyNoOrderDifference) { - queue_.insert(100, 1); - queue_.insert(101, 2); - queue_.insert(102, 3); - queue_.insert(105, 4); - queue_.insert(106, 5); - - queue_.ChangeMinKey(99); - - EXPECT_THAT(PopAllIds(), ElementsAre(1, 2, 3, 4, 5)); -} - -TEST_F(SmallPriorityQueueTest, ChangeMinKeyToMiddle) { - queue_.insert(100, 1); - queue_.insert(101, 2); - queue_.insert(102, 3); - queue_.insert(105, 4); - queue_.insert(106, 5); - - queue_.ChangeMinKey(103); - - EXPECT_THAT(PopAllIds(), ElementsAre(2, 3, 1, 4, 5)); -} - -TEST_F(SmallPriorityQueueTest, ChangeMinKeyToLast) { - queue_.insert(100, 1); - queue_.insert(101, 2); - queue_.insert(102, 3); - queue_.insert(105, 4); - queue_.insert(106, 5); - - queue_.ChangeMinKey(107); - - EXPECT_THAT(PopAllIds(), ElementsAre(2, 3, 4, 5, 1)); -} - -TEST_F(SmallPriorityQueueTest, StableSortingOrder) { - queue_.insert(100, 1); - queue_.insert(100, 2); - queue_.insert(100, 3); - queue_.insert(100, 4); - queue_.insert(100, 5); - - EXPECT_THAT(PopAllIds(), ElementsAre(1, 2, 3, 4, 5)); -} - -TEST_F(SmallPriorityQueueTest, StableSortingOrderRemoveMiddle) { - queue_.insert(100, 1); - queue_.insert(100, 2); - queue_.insert(100, 3); - queue_.insert(100, 4); - queue_.insert(100, 5); - queue_.erase(3); - - EXPECT_THAT(PopAllIds(), ElementsAre(1, 2, 4, 5)); -} - -TEST_F(SmallPriorityQueueTest, StableSortingOrderChangeMinToLast) { - queue_.insert(100, 1); - queue_.insert(100, 2); - queue_.insert(100, 3); - queue_.insert(100, 4); - queue_.insert(100, 5); - queue_.ChangeMinKey(101); - - EXPECT_THAT(PopAllIds(), ElementsAre(2, 3, 4, 5, 1)); -} - } // namespace task_queue_selector_unittest } // namespace internal } // namespace sequence_manager
diff --git a/base/task/sequence_manager/work_queue_sets.cc b/base/task/sequence_manager/work_queue_sets.cc index b538233e..b940be9 100644 --- a/base/task/sequence_manager/work_queue_sets.cc +++ b/base/task/sequence_manager/work_queue_sets.cc
@@ -10,8 +10,7 @@ namespace sequence_manager { namespace internal { -WorkQueueSets::WorkQueueSets(const char* name, Observer* observer) - : name_(name), observer_(observer) {} +WorkQueueSets::WorkQueueSets(const char* name) : name_(name) {} WorkQueueSets::~WorkQueueSets() = default; @@ -24,10 +23,7 @@ work_queue->AssignSetIndex(set_index); if (!has_enqueue_order) return; - bool was_empty = work_queue_heaps_[set_index].empty(); work_queue_heaps_[set_index].insert({enqueue_order, work_queue}); - if (was_empty) - observer_->WorkQueueSetBecameNonEmpty(set_index); } void WorkQueueSets::RemoveQueue(WorkQueue* work_queue) { @@ -39,8 +35,6 @@ size_t set_index = work_queue->work_queue_set_index(); DCHECK_LT(set_index, work_queue_heaps_.size()); work_queue_heaps_[set_index].erase(heap_handle); - if (work_queue_heaps_[set_index].empty()) - observer_->WorkQueueSetBecameEmpty(set_index); } void WorkQueueSets::ChangeSetIndex(WorkQueue* work_queue, size_t set_index) { @@ -55,12 +49,7 @@ if (!has_enqueue_order) return; work_queue_heaps_[old_set].erase(work_queue->heap_handle()); - bool was_empty = work_queue_heaps_[set_index].empty(); work_queue_heaps_[set_index].insert({enqueue_order, work_queue}); - if (work_queue_heaps_[old_set].empty()) - observer_->WorkQueueSetBecameEmpty(old_set); - if (was_empty) - observer_->WorkQueueSetBecameNonEmpty(set_index); } void WorkQueueSets::OnFrontTaskChanged(WorkQueue* work_queue) { @@ -84,10 +73,7 @@ << " set_index = " << set_index; // |work_queue| should not be in work_queue_heaps_[set_index]. DCHECK(!work_queue->heap_handle().IsValid()); - bool was_empty = work_queue_heaps_[set_index].empty(); work_queue_heaps_[set_index].insert({enqueue_order, work_queue}); - if (was_empty) - observer_->WorkQueueSetBecameNonEmpty(set_index); } void WorkQueueSets::OnPopQueue(WorkQueue* work_queue) { @@ -108,9 +94,6 @@ work_queue_heaps_[set_index].Pop(); DCHECK(work_queue_heaps_[set_index].empty() || work_queue_heaps_[set_index].Min().value != work_queue); - if (work_queue_heaps_[set_index].empty()) { - observer_->WorkQueueSetBecameEmpty(set_index); - } } } @@ -122,8 +105,6 @@ size_t set_index = work_queue->work_queue_set_index(); DCHECK_LT(set_index, work_queue_heaps_.size()); work_queue_heaps_[set_index].erase(heap_handle); - if (work_queue_heaps_[set_index].empty()) - observer_->WorkQueueSetBecameEmpty(set_index); } WorkQueue* WorkQueueSets::GetOldestQueueInSet(size_t set_index) const {
diff --git a/base/task/sequence_manager/work_queue_sets.h b/base/task/sequence_manager/work_queue_sets.h index 8e23c7a0..4889b2f 100644 --- a/base/task/sequence_manager/work_queue_sets.h +++ b/base/task/sequence_manager/work_queue_sets.h
@@ -28,16 +28,7 @@ // values are kept in sorted order. class BASE_EXPORT WorkQueueSets { public: - class Observer { - public: - virtual ~Observer() {} - - virtual void WorkQueueSetBecameEmpty(size_t set_index) = 0; - - virtual void WorkQueueSetBecameNonEmpty(size_t set_index) = 0; - }; - - WorkQueueSets(const char* name, Observer* observer); + explicit WorkQueueSets(const char* name); ~WorkQueueSets(); // O(log num queues) @@ -99,14 +90,12 @@ } }; - const char* const name_; - Observer* const observer_; - // For each set |work_queue_heaps_| has a queue of WorkQueue ordered by the // oldest task in each WorkQueue. std::array<base::internal::IntrusiveHeap<OldestTaskEnqueueOrder>, TaskQueue::kQueuePriorityCount> work_queue_heaps_; + const char* const name_; DISALLOW_COPY_AND_ASSIGN(WorkQueueSets); };
diff --git a/base/task/sequence_manager/work_queue_sets_unittest.cc b/base/task/sequence_manager/work_queue_sets_unittest.cc index ad9d320..c8426fe5 100644 --- a/base/task/sequence_manager/work_queue_sets_unittest.cc +++ b/base/task/sequence_manager/work_queue_sets_unittest.cc
@@ -17,20 +17,9 @@ namespace internal { -namespace { - -class MockObserver : public WorkQueueSets::Observer { - MOCK_METHOD1(WorkQueueSetBecameEmpty, void(size_t set_index)); - MOCK_METHOD1(WorkQueueSetBecameNonEmpty, void(size_t set_index)); -}; - -} // namespace - class WorkQueueSetsTest : public testing::Test { public: - void SetUp() override { - work_queue_sets_.reset(new WorkQueueSets("test", &mock_observer_)); - } + void SetUp() override { work_queue_sets_.reset(new WorkQueueSets("test")); } void TearDown() override { for (std::unique_ptr<WorkQueue>& work_queue : work_queues_) { @@ -63,7 +52,6 @@ return fake_task; } - MockObserver mock_observer_; std::vector<std::unique_ptr<WorkQueue>> work_queues_; std::unique_ptr<WorkQueueSets> work_queue_sets_; };
diff --git a/base/task/sequence_manager/work_queue_unittest.cc b/base/task/sequence_manager/work_queue_unittest.cc index cfb8075..23fc3ee 100644 --- a/base/task/sequence_manager/work_queue_unittest.cc +++ b/base/task/sequence_manager/work_queue_unittest.cc
@@ -20,11 +20,6 @@ namespace { -class MockObserver : public WorkQueueSets::Observer { - MOCK_METHOD1(WorkQueueSetBecameEmpty, void(size_t set_index)); - MOCK_METHOD1(WorkQueueSetBecameNonEmpty, void(size_t set_index)); -}; - void NopTask() {} struct Cancelable { @@ -52,8 +47,7 @@ work_queue_.reset(new WorkQueue(task_queue_.get(), "test", WorkQueue::QueueType::kImmediate)); - mock_observer_.reset(new MockObserver); - work_queue_sets_.reset(new WorkQueueSets("test", mock_observer_.get())); + work_queue_sets_.reset(new WorkQueueSets("test")); work_queue_sets_->AddQueue(work_queue_.get(), 0); } @@ -88,7 +82,6 @@ return fake_task; } - std::unique_ptr<MockObserver> mock_observer_; std::unique_ptr<SequenceManagerImpl> dummy_sequence_manager_; std::unique_ptr<RealTimeDomain> time_domain_; std::unique_ptr<TaskQueueImpl> task_queue_;
diff --git a/build/android/gyp/apkbuilder.py b/build/android/gyp/apkbuilder.py index 86e77a6a..b5097aa 100755 --- a/build/android/gyp/apkbuilder.py +++ b/build/android/gyp/apkbuilder.py
@@ -212,7 +212,7 @@ compress = None if (uncompress and os.path.splitext(basename)[1] == '.so' and 'android_linker' not in basename - and 'clang_rt' not in basename + and (not has_crazy_linker or 'clang_rt' not in basename) and 'crashpad_handler' not in basename): compress = False # Add prefix to prevent android install from extracting upon install.
diff --git a/build/args/headless.gn b/build/args/headless.gn index ae5e043..9a6bfd1 100644 --- a/build/args/headless.gn +++ b/build/args/headless.gn
@@ -40,3 +40,4 @@ use_libpci = false use_pulseaudio = false use_udev = false +rtc_use_pipewire = false
diff --git a/build/util/lastchange.py b/build/util/lastchange.py index 1f9de67d..fd55ce3 100755 --- a/build/util/lastchange.py +++ b/build/util/lastchange.py
@@ -7,27 +7,28 @@ lastchange.py -- Chromium revision fetching utility. """ -import argparse -import collections +import re import logging +import argparse import os import subprocess import sys -VersionInfo = collections.namedtuple("VersionInfo", - ("revision_id", "revision", "timestamp")) +class VersionInfo(object): + def __init__(self, revision_id, full_revision_string, timestamp): + self.revision_id = revision_id + self.revision = full_revision_string + self.timestamp = timestamp -class GitError(Exception): - pass def RunGitCommand(directory, command): """ Launches git subcommand. + Errors are swallowed. + Returns: - The stripped stdout of the git command. - Raises: - GitError on failure, including a nonzero return code. + A process object or None. """ command = ['git'] + command # Force shell usage under cygwin. This is a workaround for @@ -37,81 +38,61 @@ if sys.platform == 'cygwin': command = ['sh', '-c', ' '.join(command)] try: - logging.info("Executing '%s' in %s", ' '.join(command), directory) proc = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=directory, shell=(sys.platform=='win32')) - stdout, stderr = proc.communicate() - stdout = stdout.strip() - logging.debug("returncode: %d", proc.returncode) - logging.debug("stdout: %s", stdout) - logging.debug("stderr: %s", stderr) - if proc.returncode != 0 or not stdout: - raise GitError(( - "Git command 'git {}' in {} failed: " - "rc={}, stdout='{}' stderr='{}'").format( - " ".join(command), directory, proc.returncode, stdout, stderr)) - return stdout + return proc except OSError as e: - raise GitError("Git command 'git {}' in {} failed: {}".format( - " ".join(command), directory, e)) + logging.error('Command %r failed: %s' % (' '.join(command), e)) + return None -def GetMergeBase(directory, ref): + +def FetchGitRevision(directory, filter): """ - Return the merge-base of HEAD and ref. + Fetch the Git hash (and Cr-Commit-Position if any) for a given directory. - Args: - directory: The directory containing the .git directory. - ref: The ref to use to find the merge base. + Errors are swallowed. + Returns: - The git commit SHA of the merge-base as a string. + A VersionInfo object or None on error. """ - logging.debug("Calculating merge base between HEAD and %s in %s", - ref, directory) - command = ['merge-base', 'HEAD', ref] - return RunGitCommand(directory, command) + hsh = '' + git_args = ['log', '-1', '--format=%H %ct'] + if filter is not None: + git_args.append('--grep=' + filter) + proc = RunGitCommand(directory, git_args) + if proc: + output = proc.communicate()[0].strip() + if proc.returncode == 0 and output: + hsh, ct = output.split() + else: + logging.error('Git error: rc=%d, output=%r' % + (proc.returncode, output)) + if not hsh: + return None + pos = '' + proc = RunGitCommand(directory, ['cat-file', 'commit', hsh]) + if proc: + output = proc.communicate()[0] + if proc.returncode == 0 and output: + for line in reversed(output.splitlines()): + if line.startswith('Cr-Commit-Position:'): + pos = line.rsplit()[-1].strip() + break + return VersionInfo(hsh, '%s-%s' % (hsh, pos), int(ct)) -def FetchGitRevision(directory, commit_filter, start_commit="HEAD"): + +def FetchVersionInfo(directory=None, filter=None): """ Returns the last change (as a VersionInfo object) from some appropriate revision control system. - - - Args: - directory: The directory containing the .git directory. - commit_filter: A filter to supply to grep to filter commits - start_commit: A commit identifier. The result of this function - will be limited to only consider commits before the provided - commit. - Returns: - A VersionInfo object. On error all values will be 0. """ - hash_ = '' - - git_args = ['log', '-1', '--format=%H %ct'] - if commit_filter is not None: - git_args.append('--grep=' + commit_filter) - - git_args.append(start_commit) - - output = RunGitCommand(directory, git_args) - hash_, commit_timestamp = output.split() - if not hash_: - return VersionInfo('0', '0', 0) - - revision = hash_ - output = RunGitCommand(directory, ['cat-file', 'commit', hash_]) - for line in reversed(output.splitlines()): - if line.startswith('Cr-Commit-Position:'): - pos = line.rsplit()[-1].strip() - logging.debug("Found Cr-Commit-Position '%s'", pos) - revision = "{}-{}".format(hash_, pos) - break - return VersionInfo(hash_, revision, int(commit_timestamp)) - - + version_info = FetchGitRevision(directory, filter) + if not version_info: + version_info = VersionInfo('0', '0', 0) + return version_info def GetHeaderGuard(path): @@ -152,16 +133,6 @@ return header_contents -def GetGitTopDirectory(source_dir): - """Get the top git directory - the directory that contains the .git directory. - - Args: - source_dir: The directory to search. - Returns: - The output of "git rev-parse --show-toplevel" as a string - """ - return RunGitCommand(source_dir, ['rev-parse', '--show-toplevel']) - def WriteIfChanged(file_name, contents): """ Writes the specified contents to the specified file_name @@ -186,23 +157,20 @@ parser = argparse.ArgumentParser(usage="lastchange.py [options]") parser.add_argument("-m", "--version-macro", - help=("Name of C #define when using --header. Defaults to " - "LAST_CHANGE.")) + help="Name of C #define when using --header. Defaults to " + + "LAST_CHANGE.", + default="LAST_CHANGE") parser.add_argument("-o", "--output", metavar="FILE", - help=("Write last change to FILE. " - "Can be combined with --header to write both files.")) + help="Write last change to FILE. " + + "Can be combined with --header to write both files.") parser.add_argument("--header", metavar="FILE", help=("Write last change to FILE as a C/C++ header. " "Can be combined with --output to write both files.")) - parser.add_argument("--merge-base-ref", - default=None, - help=("Only consider changes since the merge " - "base between HEAD and the provided ref")) parser.add_argument("--revision-id-only", action='store_true', help=("Output the revision as a VCS revision ID only (in " "Git, a 40-character commit hash, excluding the " "Cr-Commit-Position).")) - parser.add_argument("--print-only", action="store_true", + parser.add_argument("--print-only", action='store_true', help=("Just print the revision string. Overrides any " "file-output-related options.")) parser.add_argument("-s", "--source-dir", metavar="DIR", @@ -212,14 +180,13 @@ "matches the supplied filter regex. Defaults to " "'^Change-Id:' to suppress local commits."), default='^Change-Id:') - args, extras = parser.parse_known_args(argv[1:]) logging.basicConfig(level=logging.WARNING) out_file = args.output header = args.header - commit_filter = args.filter + filter=args.filter while len(extras) and out_file is None: if out_file is None: @@ -229,37 +196,18 @@ parser.print_help() sys.exit(2) - source_dir = args.source_dir or os.path.dirname(os.path.abspath(__file__)) - try: - git_top_dir = GetGitTopDirectory(source_dir) - except GitError as e: - logging.error("Failed to get git top directory from '%s': %s", - source_dir, e) - return 2 - - if args.merge_base_ref: - try: - merge_base_sha = GetMergeBase(git_top_dir, args.merge_base_ref) - except GitError as e: - logging.error("You requested a --merge-base-ref value of '%s' but no " - "merge base could be found between it and HEAD. Git " - "reports: %s", args.merge_base_ref, e) - return 3 + if args.source_dir: + src_dir = args.source_dir else: - merge_base_sha = 'HEAD' + src_dir = os.path.dirname(os.path.abspath(__file__)) - try: - version_info = FetchGitRevision(git_top_dir, commit_filter, merge_base_sha) - except GitError as e: - logging.error("Failed to get version info: %s") - return 1 - + version_info = FetchVersionInfo(directory=src_dir, filter=filter) revision_string = version_info.revision if args.revision_id_only: revision_string = version_info.revision_id if args.print_only: - print(revision_string) + print revision_string else: contents = "LASTCHANGE=%s\n" % revision_string if not out_file and not args.header:
diff --git a/cc/mojo_embedder/async_layer_tree_frame_sink.cc b/cc/mojo_embedder/async_layer_tree_frame_sink.cc index e702ad1..286c328 100644 --- a/cc/mojo_embedder/async_layer_tree_frame_sink.cc +++ b/cc/mojo_embedder/async_layer_tree_frame_sink.cc
@@ -218,8 +218,13 @@ if (show_hit_test_borders && hit_test_region_list) hit_test_region_list->flags |= viz::HitTestRegionFlags::kHitTestDebug; - // Do not send duplicate hit-test data. - if (hit_test_region_list && !hit_test_data_changed) { + // If |hit_test_data_changed| was set or local_surface_id has been updated, + // we always send hit-test data; otherwise we check for equality with the + // last submitted hit-test data for possible optimization. + if (!hit_test_region_list) { + last_hit_test_data_ = viz::HitTestRegionList(); + } else if (!hit_test_data_changed && + local_surface_id_ == last_submitted_local_surface_id_) { if (viz::HitTestRegionList::IsEqual(*hit_test_region_list, last_hit_test_data_)) { DCHECK(!viz::HitTestRegionList::IsEqual(*hit_test_region_list, @@ -232,7 +237,7 @@ UMA_HISTOGRAM_BOOLEAN("Event.VizHitTest.HitTestDataIsEqualAccuracy", !hit_test_region_list); } else { - last_hit_test_data_ = viz::HitTestRegionList(); + last_hit_test_data_ = *hit_test_region_list; } if (last_submitted_local_surface_id_ != local_surface_id_) {
diff --git a/cc/paint/color_space_transfer_cache_entry.cc b/cc/paint/color_space_transfer_cache_entry.cc index adde337..31f2743 100644 --- a/cc/paint/color_space_transfer_cache_entry.cc +++ b/cc/paint/color_space_transfer_cache_entry.cc
@@ -14,6 +14,7 @@ DCHECK(raster_color_space.color_space.IsValid()); IPC::ParamTraits<gfx::ColorSpace>::Write(&pickle_, raster_color_space.color_space); + DCHECK_LE(pickle_.size(), UINT32_MAX); } ClientColorSpaceTransferCacheEntry::~ClientColorSpaceTransferCacheEntry() = @@ -23,8 +24,8 @@ return id_; } -size_t ClientColorSpaceTransferCacheEntry::SerializedSize() const { - return pickle_.size(); +uint32_t ClientColorSpaceTransferCacheEntry::SerializedSize() const { + return static_cast<uint32_t>(pickle_.size()); } bool ClientColorSpaceTransferCacheEntry::Serialize(
diff --git a/cc/paint/color_space_transfer_cache_entry.h b/cc/paint/color_space_transfer_cache_entry.h index baeeb4ce..4923c73 100644 --- a/cc/paint/color_space_transfer_cache_entry.h +++ b/cc/paint/color_space_transfer_cache_entry.h
@@ -29,7 +29,7 @@ const RasterColorSpace& raster_color_space); ~ClientColorSpaceTransferCacheEntry() override; uint32_t Id() const override; - size_t SerializedSize() const override; + uint32_t SerializedSize() const override; bool Serialize(base::span<uint8_t> data) const final; private:
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc index 170e55f2..3a9b9781 100644 --- a/cc/paint/image_transfer_cache_entry.cc +++ b/cc/paint/image_transfer_cache_entry.cc
@@ -69,7 +69,7 @@ : 0u; // Compute and cache the size of the data. - base::CheckedNumeric<size_t> safe_size; + base::CheckedNumeric<uint32_t> safe_size; safe_size += PaintOpWriter::HeaderBytes(); safe_size += sizeof(uint32_t); // color type safe_size += sizeof(uint32_t); // width @@ -90,7 +90,7 @@ // static base::AtomicSequenceNumber ClientImageTransferCacheEntry::s_next_id_; -size_t ClientImageTransferCacheEntry::SerializedSize() const { +uint32_t ClientImageTransferCacheEntry::SerializedSize() const { return size_; }
diff --git a/cc/paint/image_transfer_cache_entry.h b/cc/paint/image_transfer_cache_entry.h index db31ade..7b563c4 100644 --- a/cc/paint/image_transfer_cache_entry.h +++ b/cc/paint/image_transfer_cache_entry.h
@@ -31,7 +31,7 @@ uint32_t Id() const final; // ClientTransferCacheEntry implementation: - size_t SerializedSize() const final; + uint32_t SerializedSize() const final; bool Serialize(base::span<uint8_t> data) const final; private: @@ -39,7 +39,7 @@ const SkPixmap* const pixmap_; const SkColorSpace* const target_color_space_; const bool needs_mips_; - size_t size_ = 0; + uint32_t size_ = 0; static base::AtomicSequenceNumber s_next_id_; };
diff --git a/cc/paint/raw_memory_transfer_cache_entry.cc b/cc/paint/raw_memory_transfer_cache_entry.cc index aa6fb64..8f8e746 100644 --- a/cc/paint/raw_memory_transfer_cache_entry.cc +++ b/cc/paint/raw_memory_transfer_cache_entry.cc
@@ -10,15 +10,18 @@ ClientRawMemoryTransferCacheEntry::ClientRawMemoryTransferCacheEntry( std::vector<uint8_t> data) - : id_(s_next_id_.GetNext()), data_(std::move(data)) {} + : id_(s_next_id_.GetNext()), data_(std::move(data)) { + DCHECK_LE(data_.size(), UINT32_MAX); +} + ClientRawMemoryTransferCacheEntry::~ClientRawMemoryTransferCacheEntry() = default; // static base::AtomicSequenceNumber ClientRawMemoryTransferCacheEntry::s_next_id_; -size_t ClientRawMemoryTransferCacheEntry::SerializedSize() const { - return data_.size(); +uint32_t ClientRawMemoryTransferCacheEntry::SerializedSize() const { + return static_cast<uint32_t>(data_.size()); } uint32_t ClientRawMemoryTransferCacheEntry::Id() const {
diff --git a/cc/paint/raw_memory_transfer_cache_entry.h b/cc/paint/raw_memory_transfer_cache_entry.h index c6ce52af..2e9aafd4 100644 --- a/cc/paint/raw_memory_transfer_cache_entry.h +++ b/cc/paint/raw_memory_transfer_cache_entry.h
@@ -22,7 +22,7 @@ explicit ClientRawMemoryTransferCacheEntry(std::vector<uint8_t> data); ~ClientRawMemoryTransferCacheEntry() final; uint32_t Id() const final; - size_t SerializedSize() const final; + uint32_t SerializedSize() const final; bool Serialize(base::span<uint8_t> data) const final; private:
diff --git a/cc/paint/transfer_cache_entry.h b/cc/paint/transfer_cache_entry.h index 374607e2..5488aa1 100644 --- a/cc/paint/transfer_cache_entry.h +++ b/cc/paint/transfer_cache_entry.h
@@ -45,7 +45,7 @@ // Returns the serialized sized of this entry in bytes. This function will be // used to determine how much memory is going to be allocated and passed to // the Serialize() call. - virtual size_t SerializedSize() const = 0; + virtual uint32_t SerializedSize() const = 0; // Serializes the entry into the given span of memory. The size of the span is // guaranteed to be at least SerializedSize() bytes. Returns true on success
diff --git a/cc/paint/transfer_cache_unittest.cc b/cc/paint/transfer_cache_unittest.cc index f24917a..7b606ab 100644 --- a/cc/paint/transfer_cache_unittest.cc +++ b/cc/paint/transfer_cache_unittest.cc
@@ -75,7 +75,7 @@ } void CreateEntry(const ClientTransferCacheEntry& entry) { auto* context_support = ContextSupport(); - size_t size = entry.SerializedSize(); + uint32_t size = entry.SerializedSize(); void* data = context_support->MapTransferCacheEntry(size); ASSERT_TRUE(data); entry.Serialize(base::make_span(static_cast<uint8_t*>(data), size));
diff --git a/cc/test/transfer_cache_test_helper.cc b/cc/test/transfer_cache_test_helper.cc index deb3fd3..67cb937 100644 --- a/cc/test/transfer_cache_test_helper.cc +++ b/cc/test/transfer_cache_test_helper.cc
@@ -106,7 +106,7 @@ DCHECK(entries_.find(key) == entries_.end()); // Serialize data. - size_t size = client_entry.SerializedSize(); + uint32_t size = client_entry.SerializedSize(); std::unique_ptr<uint8_t[]> data(new uint8_t[size]); auto span = base::make_span(data.get(), size); bool success = client_entry.Serialize(span);
diff --git a/cc/tiles/gpu_image_decode_cache.cc b/cc/tiles/gpu_image_decode_cache.cc index 6e3ae2b..18fd073 100644 --- a/cc/tiles/gpu_image_decode_cache.cc +++ b/cc/tiles/gpu_image_decode_cache.cc
@@ -1543,7 +1543,7 @@ ClientImageTransferCacheEntry image_entry(&pixmap, color_space.get(), image_data->needs_mips); - size_t size = image_entry.SerializedSize(); + uint32_t size = image_entry.SerializedSize(); void* data = context_->ContextSupport()->MapTransferCacheEntry(size); if (data) { bool succeeded = image_entry.Serialize(
diff --git a/cc/tiles/gpu_image_decode_cache_unittest.cc b/cc/tiles/gpu_image_decode_cache_unittest.cc index 526c1dd..9c841f10 100644 --- a/cc/tiles/gpu_image_decode_cache_unittest.cc +++ b/cc/tiles/gpu_image_decode_cache_unittest.cc
@@ -132,7 +132,7 @@ void CompleteLockDiscardableTexureOnContextThread( uint32_t texture_id) override {} - void* MapTransferCacheEntry(size_t serialized_size) override { + void* MapTransferCacheEntry(uint32_t serialized_size) override { mapped_entry_size_ = serialized_size; mapped_entry_.reset(new uint8_t[serialized_size]); return mapped_entry_.get();
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 6b8ca78..052e9b7 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -1347,7 +1347,6 @@ generate_jni("test_support_jni_headers") { sources = [ - "javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java", "javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchTestBridge.java", "javatests/src/org/chromium/chrome/browser/test/MockCertVerifierRuleAndroid.java", ] @@ -1359,15 +1358,12 @@ testonly = true java_files = [ "javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchTestBridge.java", - "javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java", "javatests/src/org/chromium/chrome/browser/sync/FakeServerHelper.java", "javatests/src/org/chromium/chrome/browser/test/MockCertVerifierRuleAndroid.java", ] deps = [ ":chrome_java", "//base:base_java", - "//base:base_java_test_support", - "//components/offline_items_collection/core:core_java", "//components/sync:test_support_proto_java", "//content/public/test/android:content_java_test_support", "//third_party/android_deps:com_google_protobuf_protobuf_lite_java", @@ -1380,7 +1376,6 @@ sources = [ "../browser/android/ssl/mock_cert_verifier_rule_android.cc", "../browser/android/ssl/mock_cert_verifier_rule_android.h", - "../browser/offline_pages/android/offline_test_util_jni.cc", "../browser/offline_pages/android/prefetch_test_bridge.cc", "../browser/ssl/chrome_mock_cert_verifier.cc", "../browser/ssl/chrome_mock_cert_verifier.h", @@ -1388,7 +1383,6 @@ deps = [ ":test_support_jni_headers", "//chrome/browser", - "//components/offline_pages/core/background:test_support", ] }
diff --git a/chrome/android/java/res/layout/ephemeral_tab_caption_view.xml b/chrome/android/java/res/layout/ephemeral_tab_caption_view.xml new file mode 100644 index 0000000..6a4e61b --- /dev/null +++ b/chrome/android/java/res/layout/ephemeral_tab_caption_view.xml
@@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright 2019 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. --> + +<!-- Ephemeral Tab caption view where we display 'Open in new tab'. Hidden in + peeked state, and gets visible only when being expanded to maximized state. --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/ephemeral_tab_caption_view" + style="@style/ContextualSearchTextViewLayout" > + <TextView + android:id="@+id/ephemeral_tab_caption" + style="@style/ContextualSearchCaptionTextView" /> +</FrameLayout>
diff --git a/chrome/android/java/res/layout/url_bar.xml b/chrome/android/java/res/layout/url_bar.xml index fd1155c3..08544e8 100644 --- a/chrome/android/java/res/layout/url_bar.xml +++ b/chrome/android/java/res/layout/url_bar.xml
@@ -14,4 +14,5 @@ android:imeOptions="actionGo|flagNoExtractUi|flagNoFullscreen" android:textSize="@dimen/location_bar_url_text_size" android:inputType="textUri" - android:hint="@string/search_or_type_web_address" /> \ No newline at end of file + android:hint="@string/search_or_type_web_address" + android:importantForAutofill="no" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimator.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimator.java index 4402ee6..05ece2d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimator.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/animation/CompositorAnimator.java
@@ -45,8 +45,6 @@ /** The list of frame update listeners for this animation. */ private final ArrayList<AnimatorUpdateListener> mAnimatorUpdateListeners = new ArrayList<>(); - private FloatProperty mFloatProperty; - /** * A cached copy of the list of {@link AnimatorUpdateListener}s to prevent allocating a new list * every update. @@ -137,7 +135,6 @@ animator.setDuration(durationMs); animator.addUpdateListener( (CompositorAnimator a) -> property.setValue(target, a.getAnimatedValue())); - animator.setFloatProperty(property); animator.setInterpolator(interpolator); return animator; } @@ -232,17 +229,6 @@ mAnimatorUpdateListeners.add(listener); } - private void setFloatProperty(FloatProperty property) { - mFloatProperty = property; - } - - /** - * @return Whether this animation is of the given FloatProperty. - */ - public boolean isOfFloatProperty(FloatProperty property) { - return mFloatProperty == property; - } - /** * @return Whether or not the animation has ended after being started. If the animation is * started after ending, this value will be reset to true. @@ -284,7 +270,6 @@ public void removeAllListeners() { mListeners.clear(); mAnimatorUpdateListeners.clear(); - mFloatProperty = null; } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java index 5b540eb..66ca809 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java
@@ -5,35 +5,78 @@ package org.chromium.chrome.browser.compositor.bottombar.ephemeraltab; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import android.widget.TextView; import org.chromium.chrome.R; -import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; -import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelInflater; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; /** * Top control used for ephemeral tab. */ -public class EphemeralTabBarControl extends OverlayPanelInflater { - /** - * The tab title View. - */ - private TextView mBarText; +public class EphemeralTabBarControl { + /** Full opacity -- fully visible. */ + private static final float SOLID_OPAQUE = 1.0f; + + /** Transparent opacity -- completely transparent (not visible). */ + private static final float SOLID_TRANSPARENT = 0.0f; + + private final EphemeralTabTitleControl mTitle; + private final EphemeralTabCaptionControl mCaption; + + // Dimensions used for laying out the controls in the bar. + private final float mTextLayerMinHeight; + private final float mTitleCaptionSpacing; /** * @param panel The panel. * @param context The Android Context used to inflate the View. * @param container The container View used to inflate the View. - * @param resourceLoader The resource loader that will handle the snapshot capturing. + * @param loader The resource loader that will handle the snapshot capturing. */ - public EphemeralTabBarControl(OverlayPanel panel, Context context, ViewGroup container, - DynamicResourceLoader resourceLoader) { - super(panel, R.layout.ephemeral_tab_text_view, R.id.ephemeral_tab_text_view, context, - container, resourceLoader); - invalidate(); + public EphemeralTabBarControl(EphemeralTabPanel panel, Context context, ViewGroup container, + DynamicResourceLoader loader) { + mTitle = new EphemeralTabTitleControl(panel, context, container, loader); + mCaption = panel.canPromoteToNewTab() + ? new EphemeralTabCaptionControl(panel, context, container, loader) + : null; + mTextLayerMinHeight = context.getResources().getDimension( + R.dimen.contextual_search_text_layer_min_height); + mTitleCaptionSpacing = + context.getResources().getDimension(R.dimen.contextual_search_term_caption_spacing); + } + + /** + * Returns the minimum height that the text layer (containing the title and the caption) + * should be. + */ + public float getTextLayerMinHeight() { + return mTextLayerMinHeight; + } + + /** + * Returns the spacing that should be placed between the title and the caption. + */ + public float getTitleCaptionSpacing() { + return mTitleCaptionSpacing; + } + + /** + * Updates this bar when in transition to closed/peeked states. + * @param percentage The percentage to the more opened state. + */ + public void updateForCloseOrPeek(float percentage) { + if (percentage == SOLID_OPAQUE) updateForMaximize(SOLID_TRANSPARENT); + + // When the panel is completely closed the caption should be hidden. + if (percentage == SOLID_TRANSPARENT && mCaption != null) mCaption.hide(); + } + + /** + * Updates this bar when in transition to maximized states. + * @param percentage The percentage to the more opened state. + */ + public void updateForMaximize(float percentage) { + if (mCaption != null) mCaption.updatePanelForMaximization(percentage); } /** @@ -41,15 +84,38 @@ * @param text The string to set the text to. */ public void setBarText(String text) { - inflate(); - mBarText.setText(text); - invalidate(); + mTitle.setBarText(text); } - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - View view = getView(); - mBarText = (TextView) view.findViewById(R.id.ephemeral_tab_text); + /** + * @return {@link EphemeralTabTitleControl} object. + */ + public EphemeralTabTitleControl getTitleControl() { + return mTitle; + } + + /** + * @return {@link EphemeralTabCaptionControl} object. + */ + public EphemeralTabCaptionControl getCaptionControl() { + return mCaption; + } + + /** + * Gets the current animation percentage for the Caption control, which guides the vertical + * position and opacity of the caption. + * @return The animation percentage ranging from 0.0 to 1.0. + * + */ + public float getCaptionAnimationPercentage() { + return mCaption != null ? mCaption.getAnimationPercentage() : 0; + } + + /** + * Removes the bottom bar views from the parent container. + */ + public void destroy() { + mTitle.destroy(); + if (mCaption != null) mCaption.destroy(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java new file mode 100644 index 0000000..9f07e901 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java
@@ -0,0 +1,124 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.compositor.bottombar.ephemeraltab; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater; +import org.chromium.ui.resources.dynamics.DynamicResourceLoader; + +/** + * Controls the Caption View that is shown at the bottom of the control and used + * as a dynamic resource. + */ +public class EphemeralTabCaptionControl extends OverlayPanelTextViewInflater { + /** The caption View. */ + private TextView mCaption; + + /** Whether the caption is showing. */ + private boolean mShowingCaption; + + /** The caption visibility. */ + private boolean mIsVisible; + + /** + * The caption animation percentage, which controls how and where to draw. It is + * 0 when the Contextual Search bar is peeking and 1 when it is maxmized. + */ + private float mAnimationPercentage; + + /** + * @param panel The panel. + * @param context The Android Context used to inflate the View. + * @param container The container View used to inflate the View. + * @param resourceLoader The resource loader that will handle the snapshot capturing. + */ + public EphemeralTabCaptionControl(OverlayPanel panel, Context context, ViewGroup container, + DynamicResourceLoader resourceLoader) { + super(panel, R.layout.ephemeral_tab_caption_view, R.id.ephemeral_tab_caption_view, context, + container, resourceLoader); + } + + /** + * Updates the caption when in transition between peeked to maximized states. + * @param percentage The percentage to the more opened state. + */ + public void updatePanelForMaximization(float percentage) { + // If the caption is not showing, show it now. + if (!mShowingCaption && percentage > 0.f) { + mShowingCaption = true; + + if (mCaption == null) { + // |mCaption| gets initialized synchronously in |onFinishInflate|. + inflate(); + mCaption.setText(R.string.contextmenu_open_in_new_tab); + } + invalidate(); + mIsVisible = true; + } + + mAnimationPercentage = percentage; + if (mAnimationPercentage == 0.f) mShowingCaption = false; + } + + /** + * Hides the caption. + */ + public void hide() { + if (mShowingCaption) { + mIsVisible = false; + mAnimationPercentage = 0.f; + } + } + + /** + * Controls whether the caption is visible and can be rendered. + * The caption must be visible in order to draw it and take a snapshot. + * Even though the caption is visible the user might not be able to see it due to a + * completely transparent opacity associated with an animation percentage of zero. + * @return Whether the caption is visible or not. + */ + public boolean getIsVisible() { + return mIsVisible; + } + + /** + * Gets the animation percentage which controls the drawing of the caption and how high to + * position it in the Bar. + * @return The current percentage ranging from 0.0 to 1.0. + */ + public float getAnimationPercentage() { + return mAnimationPercentage; + } + + /** + * @return The text currently showing in the caption view. + */ + public CharSequence getCaptionText() { + return mCaption.getText(); + } + + // OverlayPanelTextViewInflater + + @Override + protected TextView getTextView() { + return mCaption; + } + + // OverlayPanelInflater + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + + View view = getView(); + mCaption = (TextView) view.findViewById(R.id.ephemeral_tab_caption); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java index e40e1c3..48d30234 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java
@@ -23,14 +23,16 @@ import org.chromium.chrome.browser.compositor.layouts.eventfilter.OverlayPanelEventFilter; import org.chromium.chrome.browser.compositor.scene_layer.EphemeralTabSceneLayer; import org.chromium.chrome.browser.compositor.scene_layer.SceneOverlayLayer; +import org.chromium.chrome.browser.tabmodel.TabModel; +import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.WebContents; +import org.chromium.ui.base.PageTransition; import org.chromium.ui.resources.ResourceManager; /** * The panel containing an ephemeral tab. * TODO(jinsukkim): Write tests. * Add animation effect upon opening ephemeral tab. - * Bring back the bottom bar animation hidden behind ephemeral tab. */ public class EphemeralTabPanel extends OverlayPanel { /** The compositor layer used for drawing the panel. */ @@ -42,6 +44,9 @@ /** True if the Tab from which the panel is opened is in incognito mode. */ private boolean mIsIncognito; + /** Url for which this epehemral tab was created. */ + private String mUrl; + /** * Checks if this feature (a.k.a. "Sneak peek") for html and image is supported. * @return {@code true} if the feature is enabled. @@ -121,7 +126,8 @@ @Override public SceneOverlayLayer getUpdatedSceneOverlayTree(RectF viewport, RectF visibleViewport, LayerTitleCache layerTitleCache, ResourceManager resourceManager, float yOffset) { - mSceneLayer.update(resourceManager, this, getBarTextViewId(), 1.0f); + mSceneLayer.update(resourceManager, this, getBarControl(), + getBarControl().getTitleControl(), getBarControl().getCaptionControl()); return mSceneLayer; } @@ -140,16 +146,28 @@ if (isCoordinateInsideCloseButton(x)) { closePanel(StateChangeReason.CLOSE_BUTTON, true); } else { - maximizePanel(StateChangeReason.SEARCH_BAR_TAP); + if (isPeeking()) { + maximizePanel(StateChangeReason.SEARCH_BAR_TAP); + } else if (canPromoteToNewTab() && mUrl != null) { + closePanel(StateChangeReason.TAB_PROMOTION, false); + mActivity.getCurrentTabCreator().createNewTab( + new LoadUrlParams(mUrl, PageTransition.LINK), + TabModel.TabLaunchType.FROM_LINK, + mActivity.getActivityTabProvider().getActivityTab()); + } } } + boolean canPromoteToNewTab() { + return !mActivity.isCustomTab(); + } + // Panel base methods @Override public void destroyComponents() { super.destroyComponents(); - destroyEphemeralTabBarControl(); + destroyBarControl(); } @Override @@ -168,6 +186,18 @@ if (mSceneLayer != null) mSceneLayer.hideTree(); } + @Override + protected void updatePanelForCloseOrPeek(float percentage) { + super.updatePanelForCloseOrPeek(percentage); + getBarControl().updateForCloseOrPeek(percentage); + } + + @Override + protected void updatePanelForMaximization(float percentage) { + super.updatePanelForMaximization(percentage); + getBarControl().updateForMaximize(percentage); + } + /** * Request opening the ephemeral tab panel when triggered from context menu. * @param url URL of the content to open in the panel @@ -175,34 +205,29 @@ * @param isIncognito {@link True} if the panel is opened from an incognito tab. */ public void requestOpenPanel(String url, String text, boolean isIncognito) { + if (isShowing()) closePanel(StateChangeReason.RESET, false); mIsIncognito = isIncognito; + mUrl = url; loadUrlInPanel(url); WebContents panelWebContents = getWebContents(); if (panelWebContents != null) panelWebContents.onShow(); - getEphemeralTabBarControl().setBarText(text); + getBarControl().setBarText(text); requestPanelShow(StateChangeReason.CLICK); } @Override public void onLayoutChanged(float width, float height, float visibleViewportOffsetY) { - if (width != getWidth()) destroyEphemeralTabBarControl(); + if (width != getWidth()) destroyBarControl(); super.onLayoutChanged(width, height, visibleViewportOffsetY); } private EphemeralTabBarControl mEphemeralTabBarControl; /** - * @return The Id of the Search Term View. - */ - public int getBarTextViewId() { - return getEphemeralTabBarControl().getViewId(); - } - - /** * Creates the EphemeralTabBarControl, if needed. The Views are set to INVISIBLE, because * they won't actually be displayed on the screen (their snapshots will be displayed instead). */ - protected EphemeralTabBarControl getEphemeralTabBarControl() { + private EphemeralTabBarControl getBarControl() { assert mContainerView != null; assert mResourceLoader != null; if (mEphemeralTabBarControl == null) { @@ -216,7 +241,7 @@ /** * Destroys the EphemeralTabBarControl. */ - protected void destroyEphemeralTabBarControl() { + private void destroyBarControl() { if (mEphemeralTabBarControl != null) { mEphemeralTabBarControl.destroy(); mEphemeralTabBarControl = null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java new file mode 100644 index 0000000..09d68aa --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java
@@ -0,0 +1,55 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.compositor.bottombar.ephemeraltab; + +import android.content.Context; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.chromium.chrome.R; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater; +import org.chromium.ui.resources.dynamics.DynamicResourceLoader; + +/** + * Title control showing URL for ephemeral tab. + */ +public class EphemeralTabTitleControl extends OverlayPanelTextViewInflater { + private TextView mBarText; + + /** + * @param panel The panel. + * @param context The Android Context used to inflate the View. + * @param container The container View used to inflate the View. + * @param resourceLoader The resource loader that will handle the snapshot capturing. + */ + public EphemeralTabTitleControl(OverlayPanel panel, Context context, ViewGroup container, + DynamicResourceLoader resourceLoader) { + super(panel, R.layout.ephemeral_tab_text_view, R.id.ephemeral_tab_text_view, context, + container, resourceLoader); + invalidate(); + } + + void setBarText(String text) { + if (mBarText == null) inflate(); + mBarText.setText(text); + invalidate(); + } + + // OverlayPanelTextViewInflater + + @Override + protected TextView getTextView() { + return mBarText; + } + + // OverlayPanelInflater + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mBarText = (TextView) getView().findViewById(R.id.ephemeral_tab_text); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java index 0fe3d76..10654f5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -4,8 +4,8 @@ package org.chromium.chrome.browser.compositor.layouts.phone; -import android.animation.Animator; -import android.animation.AnimatorSet; +import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.createAnimation; + import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; @@ -22,7 +22,8 @@ import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.compositor.LayerTitleCache; import org.chromium.chrome.browser.compositor.animation.CompositorAnimator; -import org.chromium.chrome.browser.compositor.animation.FloatProperty; +import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation; +import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable; import org.chromium.chrome.browser.compositor.layouts.Layout; import org.chromium.chrome.browser.compositor.layouts.LayoutManager; import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost; @@ -62,45 +63,14 @@ /** * Base class for layouts that show one or more stacks of tabs. */ -public abstract class StackLayoutBase extends Layout { - private static final FloatProperty<StackLayoutBase> INNER_MARGIN_PERCENT = - new FloatProperty<StackLayoutBase>("") { - @Override - public void setValue(StackLayoutBase layoutBase, float v) { - layoutBase.setInnerMarginPercent(v); - } - - @Override - public Float get(StackLayoutBase layoutTab) { - return null; - } - }; - - private static final FloatProperty<StackLayoutBase> STACK_OFFSET_Y_PERCENT = - new FloatProperty<StackLayoutBase>("") { - @Override - public void setValue(StackLayoutBase layoutBase, float v) { - layoutBase.setStackOffsetYPercent(v); - } - - @Override - public Float get(StackLayoutBase layoutTab) { - return null; - } - }; - - private static final FloatProperty<StackLayoutBase> STACK_SNAP = - new FloatProperty<StackLayoutBase>("") { - @Override - public void setValue(StackLayoutBase layoutBase, float v) { - layoutBase.setStackSnap(v); - } - - @Override - public Float get(StackLayoutBase layoutTab) { - return null; - } - }; +public abstract class StackLayoutBase extends Layout implements Animatable { + @IntDef({Property.INNER_MARGIN_PERCENT, Property.STACK_SNAP, Property.STACK_OFFSET_Y_PERCENT}) + @Retention(RetentionPolicy.SOURCE) + public @interface Property { + int INNER_MARGIN_PERCENT = 0; + int STACK_SNAP = 1; + int STACK_OFFSET_Y_PERCENT = 2; + } @IntDef({DragDirection.NONE, DragDirection.HORIZONTAL, DragDirection.VERTICAL}) @Retention(RetentionPolicy.SOURCE) @@ -224,7 +194,7 @@ private StackLayoutGestureHandler mGestureHandler; - private AnimatorSet mLayoutAnimations; + private ChromeAnimation<Animatable> mLayoutAnimations; private class StackLayoutGestureHandler implements GestureHandler { @Override @@ -379,34 +349,6 @@ } /** - * Sets the stack offset percent for vertical axis. - * - * @param v Value to set. - */ - public void setStackOffsetYPercent(float v) { - mStackOffsetYPercent = v; - } - - /** - * Sets the inner margin percent. - * - * @param v Value to set. - */ - public void setInnerMarginPercent(float v) { - mInnerMarginPercent = v; - } - - /** - * Sets the stack stap value. - * - * @param v Value to set. - */ - public void setStackSnap(float v) { - mRenderedScrollOffset = v; - mScrollIndexOffset = v; - } - - /** * Whether or not the HorizontalTabSwitcherAndroid flag (which enables the new horizontal tab * switcher in both portrait and landscape mode) is enabled. */ @@ -706,9 +648,10 @@ boolean animationsWasDone = true; if (mLayoutAnimations != null) { if (jumpToEnd) { - mLayoutAnimations.end(); + animationsWasDone = mLayoutAnimations.finished(); + mLayoutAnimations.updateAndFinish(); } else { - animationsWasDone = !mLayoutAnimations.isRunning(); + animationsWasDone = mLayoutAnimations.update(time); } if (animationsWasDone || jumpToEnd) { @@ -832,23 +775,23 @@ protected void startMarginAnimation(boolean enter, boolean showMargin) { // Any outstanding animations must be cancelled to avoid race condition. - cancelAnimation(INNER_MARGIN_PERCENT); + cancelAnimation(this, Property.INNER_MARGIN_PERCENT); float start = mInnerMarginPercent; float end = enter && showMargin ? 1.0f : 0.0f; if (start != end) { - addToAnimation(INNER_MARGIN_PERCENT, start, end, 200, 0); + addToAnimation(this, Property.INNER_MARGIN_PERCENT, start, end, 200, 0); } } private void startYOffsetAnimation(boolean enter) { // Any outstanding animations must be cancelled to avoid race condition. - cancelAnimation(STACK_OFFSET_Y_PERCENT); + cancelAnimation(this, Property.STACK_OFFSET_Y_PERCENT); float start = mStackOffsetYPercent; float end = enter ? 1.f : 0.f; if (start != end) { - addToAnimation(STACK_OFFSET_Y_PERCENT, start, end, 300, 0); + addToAnimation(this, Property.STACK_OFFSET_Y_PERCENT, start, end, 300, 0); } } @@ -1189,7 +1132,7 @@ * @param delta The amount to scroll by. */ private void scrollStacks(float delta) { - cancelAnimation(STACK_SNAP); + cancelAnimation(this, Property.STACK_SNAP); float fullDistance = getFullScrollDistance(); mScrollIndexOffset += MathUtils.flipSignIf(delta / fullDistance, !isUsingHorizontalLayout() && LocalizationUtils.isLayoutRtl()); @@ -1217,16 +1160,16 @@ * incognito to non-incognito, which leaves the up event in the incognito side. */ private void finishScrollStacks() { - cancelAnimation(STACK_SNAP); + cancelAnimation(this, Property.STACK_SNAP); final int currentModelIndex = getTabStackIndex(); float delta = Math.abs(currentModelIndex + mRenderedScrollOffset); float target = -currentModelIndex; if (delta != 0) { long duration = FLING_MIN_DURATION + (long) Math.abs(delta * getFullScrollDistance() / mFlingSpeed); - addToAnimation(STACK_SNAP, mRenderedScrollOffset, target, duration, 0); + addToAnimation(this, Property.STACK_SNAP, mRenderedScrollOffset, target, duration, 0); } else { - setStackSnap(target); + setProperty(Property.STACK_SNAP, target); onAnimationFinished(); } } @@ -1545,6 +1488,30 @@ } /** + * Sets properties for animations. + * @param prop The property to update + * @param p New value of the property + */ + @Override + public void setProperty(@Property int prop, float p) { + switch (prop) { + case Property.STACK_SNAP: + mRenderedScrollOffset = p; + mScrollIndexOffset = p; + break; + case Property.INNER_MARGIN_PERCENT: + mInnerMarginPercent = p; + break; + case Property.STACK_OFFSET_Y_PERCENT: + mStackOffsetYPercent = p; + break; + } + } + + @Override + public void onPropertyAnimationFinished(@Property int prop) {} + + /** * Called by the stacks whenever they start an animation. */ public void onStackAnimationStarted() { @@ -1581,20 +1548,20 @@ } /** - * Creates an {@link CompositorAnimator} and adds it to the animation. + * Creates an {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation + * .AnimatableAnimation} and adds it to the animation. * Automatically sets the start value at the beginning of the animation. */ - protected void addToAnimation(FloatProperty<StackLayoutBase> property, float start, float end, - long duration, long startTime) { - if (mLayoutAnimations == null) mLayoutAnimations = new AnimatorSet(); - - CompositorAnimator compositorAnimator = CompositorAnimator.ofFloatProperty( - getAnimationHandler(), this, property, start, end, duration); - compositorAnimator.setStartDelay(startTime); - - mLayoutAnimations.playTogether(compositorAnimator); - mLayoutAnimations.start(); - + protected void addToAnimation( + Animatable object, int prop, float start, float end, long duration, long startTime) { + ChromeAnimation.Animation<Animatable> component = createAnimation(object, prop, start, end, + duration, startTime, false, CompositorAnimator.DECELERATE_INTERPOLATOR); + if (mLayoutAnimations == null || mLayoutAnimations.finished()) { + mLayoutAnimations = new ChromeAnimation<Animatable>(); + mLayoutAnimations.start(); + } + component.start(); + mLayoutAnimations.add(component); requestUpdate(); } @@ -1602,7 +1569,7 @@ protected void forceAnimationToFinish() { super.forceAnimationToFinish(); if (mLayoutAnimations != null) { - mLayoutAnimations.end(); + mLayoutAnimations.updateAndFinish(); mLayoutAnimations = null; } } @@ -1612,18 +1579,13 @@ * @param object The object being animated. * @param prop The property to search for. */ - protected void cancelAnimation(FloatProperty<StackLayoutBase> property) { - if (mLayoutAnimations == null) return; - - for (Animator animator : mLayoutAnimations.getChildAnimations()) { - CompositorAnimator a = (CompositorAnimator) animator; - if (a.isOfFloatProperty(property)) a.cancel(); - } + protected void cancelAnimation(Animatable object, int prop) { + if (mLayoutAnimations != null) mLayoutAnimations.cancel(object, prop); } @Override @VisibleForTesting public boolean isLayoutAnimating() { - return mLayoutAnimations != null && mLayoutAnimations.isRunning(); + return mLayoutAnimations != null && !mLayoutAnimations.finished(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java index 2d6e7495..2ecd971 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java
@@ -4,9 +4,14 @@ package org.chromium.chrome.browser.compositor.scene_layer; +import android.support.annotation.Nullable; + import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.R; -import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; +import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabBarControl; +import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCaptionControl; +import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel; +import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabTitleControl; import org.chromium.content_public.browser.WebContents; import org.chromium.ui.resources.ResourceManager; @@ -35,37 +40,50 @@ * Update the scene layer to draw an OverlayPanel. * @param resourceManager Manager to get view and image resources. * @param panel The OverlayPanel to render. - * @param barTextViewId The ID of the view containing the ephemeral tab bar. - * @param barTextOpacity The opacity of the text specified by {@code barTextViewId}. + * @param bar {@link EphemeralTabBarControl} object. + * @param title {@link EphemeralTabTitleControl} object. + * @param caption {@link EphemeralTabCaptionControl} object. */ - public void update(ResourceManager resourceManager, OverlayPanel panel, int barTextViewId, - float barTextOpacity) { + public void update(ResourceManager resourceManager, EphemeralTabPanel panel, + EphemeralTabBarControl bar, EphemeralTabTitleControl title, + @Nullable EphemeralTabCaptionControl caption) { // Don't try to update the layer if not initialized or showing. if (resourceManager == null || !panel.isShowing()) return; if (!mIsInitialized) { nativeCreateEphemeralTabLayer(mNativePtr, resourceManager); // TODO(jinsukkim): Find the right icon/background resource for the tab bar. - nativeSetResourceIds(mNativePtr, barTextViewId, + nativeSetResourceIds(mNativePtr, title.getViewId(), R.drawable.contextual_search_bar_background, R.drawable.modern_toolbar_shadow, R.drawable.infobar_chrome, R.drawable.btn_close); mIsInitialized = true; } + + int titleViewId = title.getViewId(); + int captionViewId = 0; + float captionAnimationPercentage = 0.f; + boolean captionVisible = false; + if (caption != null) { + captionViewId = caption.getViewId(); + captionAnimationPercentage = caption.getAnimationPercentage(); + captionVisible = caption.getIsVisible(); + } boolean isProgressBarVisible = panel.isProgressBarVisible(); float progressBarHeight = panel.getProgressBarHeight(); float progressBarOpacity = panel.getProgressBarOpacity(); int progressBarCompletion = panel.getProgressBarCompletion(); WebContents panelWebContents = panel.getWebContents(); - nativeUpdate(mNativePtr, R.drawable.progress_bar_background, - R.drawable.progress_bar_foreground, mDpToPx, panel.getBasePageBrightness(), - panel.getBasePageY() * mDpToPx, panelWebContents, panel.getOffsetX() * mDpToPx, - panel.getOffsetY() * mDpToPx, panel.getWidth() * mDpToPx, - panel.getHeight() * mDpToPx, panel.getBarMarginSide() * mDpToPx, - panel.getBarHeight() * mDpToPx, barTextOpacity, panel.isBarBorderVisible(), - panel.getBarBorderHeight() * mDpToPx, panel.getBarShadowVisible(), - panel.getBarShadowOpacity(), isProgressBarVisible, progressBarHeight * mDpToPx, - progressBarOpacity, progressBarCompletion); + nativeUpdate(mNativePtr, titleViewId, captionViewId, captionAnimationPercentage, + bar.getTextLayerMinHeight(), bar.getTitleCaptionSpacing(), captionVisible, + R.drawable.progress_bar_background, R.drawable.progress_bar_foreground, mDpToPx, + panel.getBasePageBrightness(), panel.getBasePageY() * mDpToPx, panelWebContents, + panel.getOffsetX() * mDpToPx, panel.getOffsetY() * mDpToPx, + panel.getWidth() * mDpToPx, panel.getHeight() * mDpToPx, + panel.getBarMarginSide() * mDpToPx, panel.getBarHeight() * mDpToPx, + panel.isBarBorderVisible(), panel.getBarBorderHeight() * mDpToPx, + panel.getBarShadowVisible(), panel.getBarShadowOpacity(), isProgressBarVisible, + progressBarHeight * mDpToPx, progressBarOpacity, progressBarCompletion); } @Override @@ -108,11 +126,13 @@ private native void nativeSetResourceIds(long nativeEphemeralTabSceneLayer, int barTextResourceId, int barBackgroundResourceId, int barShadowResourceId, int panelIconResourceId, int closeIconResourceId); - private native void nativeUpdate(long nativeEphemeralTabSceneLayer, - int progressBarBackgroundResourceId, int progressBarResourceId, float dpToPx, - float basePageBrightness, float basePageYOffset, WebContents webContents, float panelX, - float panelY, float panelWidth, float panelHeight, float barMarginSide, float barHeight, - float textOpacity, boolean barBorderVisible, float barBorderHeight, - boolean barShadowVisible, float barShadowOpacity, boolean isProgressBarVisible, - float progressBarHeight, float progressBarOpacity, int progressBarCompletion); + private native void nativeUpdate(long nativeEphemeralTabSceneLayer, int titleViewId, + int captionViewId, float captionAnimationPercentage, float textLayerMinHeight, + float titleCaptionSpacing, boolean captionVisible, int progressBarBackgroundResourceId, + int progressBarResourceId, float dpToPx, float basePageBrightness, + float basePageYOffset, WebContents webContents, float panelX, float panelY, + float panelWidth, float panelHeight, float barMarginSide, float barHeight, + boolean barBorderVisible, float barBorderHeight, boolean barShadowVisible, + float barShadowOpacity, boolean isProgressBarVisible, float progressBarHeight, + float progressBarOpacity, int progressBarCompletion); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java index 5e6a59c..e0c7821 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -34,22 +34,17 @@ import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.chrome.browser.ChromeApplication; -import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.download.DownloadNotificationUmaHelper.UmaDownloadResumption; import org.chromium.chrome.browser.download.items.OfflineContentAggregatorNotificationBridgeUiFactory; import org.chromium.chrome.browser.init.BrowserParts; import org.chromium.chrome.browser.init.ChromeBrowserInitializer; import org.chromium.chrome.browser.init.EmptyBrowserParts; -import org.chromium.chrome.browser.init.ServiceManagerStartupUtils; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.components.offline_items_collection.ContentId; import org.chromium.components.offline_items_collection.LegacyHelpers; import org.chromium.components.offline_items_collection.PendingState; import org.chromium.content_public.browser.BrowserStartupController; -import java.util.HashSet; -import java.util.Set; - /** * Class that spins up native when an interaction with a notification happens and passes the * relevant information on to native. @@ -202,10 +197,7 @@ @Override public boolean startServiceManagerOnly() { if (!LegacyHelpers.isLegacyDownload(id)) return false; - Set<String> features = new HashSet<String>(); - features.add(ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD); - features.add(ChromeFeatureList.NETWORK_SERVICE); - return ServiceManagerStartupUtils.canStartServiceManager(features) + return DownloadUtils.shouldStartServiceManagerOnly() && !ACTION_DOWNLOAD_OPEN.equals(intent.getAction()); } };
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 index 265beeb..e3e5d66 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -42,6 +42,7 @@ import org.chromium.chrome.browser.download.ui.DownloadHistoryItemWrapper.OfflineItemWrapper; import org.chromium.chrome.browser.feature_engagement.ScreenshotTabObserver; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; +import org.chromium.chrome.browser.init.ServiceManagerStartupUtils; import org.chromium.chrome.browser.media.MediaViewerUtils; import org.chromium.chrome.browser.offlinepages.DownloadUiActionFlags; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; @@ -81,9 +82,11 @@ import java.util.Calendar; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -999,6 +1002,14 @@ && entry.isAutoResumable; } + /** @return Whether we should start service manager only, based off the features enabled. */ + public static boolean shouldStartServiceManagerOnly() { + Set<String> features = new HashSet<String>(); + features.add(ChromeFeatureList.SERVICE_MANAGER_FOR_DOWNLOAD); + features.add(ChromeFeatureList.NETWORK_SERVICE); + return ServiceManagerStartupUtils.canStartServiceManager(features); + } + /** * Format the number of bytes into KB, or MB, or GB and return the corresponding string * resource. Uses default download-related set of strings.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java index 80a55b62e..a21f939 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java
@@ -10,6 +10,7 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask; import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask.StartBeforeNativeResult; +import org.chromium.chrome.browser.download.DownloadUtils; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.components.background_task_scheduler.TaskParameters; import org.chromium.components.download.DownloadTaskType; @@ -22,6 +23,8 @@ * Entry point for the download service to perform desired action when the task is fired by the * scheduler. The scheduled task is executed for the regular profile and also for incognito profile * if an incognito profile exists. + * TODO(shaktisahu): Since we probably don't need to run tasks for incognito profile, cleanup this + * class and remove any reference to profiles. */ @JNINamespace("download::android") public class DownloadBackgroundTask extends NativeBackgroundTask { @@ -37,6 +40,9 @@ // Keeps track of in progress tasks which haven't invoked their {@link TaskFinishedCallback}s. private Map<Integer, PendingTaskCounter> mPendingTaskCounters = new HashMap<>(); + @DownloadTaskType + private int mCurrentTaskType; + @Override protected @StartBeforeNativeResult int onStartTaskBeforeNativeLoaded( Context context, TaskParameters taskParameters, TaskFinishedCallback callback) { @@ -59,34 +65,42 @@ // In case of future upgrades, we would need to build an intent for the old version and // validate that this code still works. This would require decoupling this immediate class // from native as well. - @DownloadTaskType - final int taskType = - taskParameters.getExtras().getInt(DownloadTaskScheduler.EXTRA_TASK_TYPE); + mCurrentTaskType = taskParameters.getExtras().getInt(DownloadTaskScheduler.EXTRA_TASK_TYPE); Callback<Boolean> wrappedCallback = new Callback<Boolean>() { @Override public void onResult(Boolean needsReschedule) { - if (mPendingTaskCounters.get(taskType) == null) return; + if (mPendingTaskCounters.get(mCurrentTaskType) == null) return; boolean noPendingCallbacks = - decrementPendingCallbackCount(taskType, needsReschedule); + decrementPendingCallbackCount(mCurrentTaskType, needsReschedule); if (noPendingCallbacks) { - callback.taskFinished(mPendingTaskCounters.get(taskType).needsReschedule); - mPendingTaskCounters.remove(taskType); + callback.taskFinished( + mPendingTaskCounters.get(mCurrentTaskType).needsReschedule); + mPendingTaskCounters.remove(mCurrentTaskType); } } }; - Profile profile = Profile.getLastUsedProfile().getOriginalProfile(); - incrementPendingCallbackCount(taskType); - nativeStartBackgroundTask(profile, taskType, wrappedCallback); + Profile profile = supportsServiceManagerOnly() + ? null + : Profile.getLastUsedProfile().getOriginalProfile(); + incrementPendingCallbackCount(mCurrentTaskType); + nativeStartBackgroundTask(profile, mCurrentTaskType, wrappedCallback); - if (profile.hasOffTheRecordProfile()) { - incrementPendingCallbackCount(taskType); - nativeStartBackgroundTask(profile.getOffTheRecordProfile(), taskType, wrappedCallback); + if (profile != null && profile.hasOffTheRecordProfile()) { + incrementPendingCallbackCount(mCurrentTaskType); + nativeStartBackgroundTask( + profile.getOffTheRecordProfile(), mCurrentTaskType, wrappedCallback); } } + @Override + protected boolean supportsServiceManagerOnly() { + return mCurrentTaskType == DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK + && DownloadUtils.shouldStartServiceManagerOnly(); + } + private void incrementPendingCallbackCount(@DownloadTaskType int taskType) { PendingTaskCounter taskCounter = mPendingTaskCounters.containsKey(taskType) ? mPendingTaskCounters.get(taskType) @@ -117,10 +131,12 @@ int taskType = taskParameters.getExtras().getInt(DownloadTaskScheduler.EXTRA_TASK_TYPE); mPendingTaskCounters.remove(taskType); - Profile profile = Profile.getLastUsedProfile().getOriginalProfile(); + Profile profile = supportsServiceManagerOnly() + ? null + : Profile.getLastUsedProfile().getOriginalProfile(); boolean needsReschedule = nativeStopBackgroundTask(profile, taskType); - if (profile.hasOffTheRecordProfile()) { + if (profile != null && profile.hasOffTheRecordProfile()) { needsReschedule |= nativeStopBackgroundTask(profile.getOffTheRecordProfile(), taskType); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java index e54d9e3..3b71fa1f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java
@@ -29,6 +29,7 @@ public static final String EXTRA_TASK_TYPE = "extra_task_type"; static final long TWELVE_HOURS_IN_SECONDS = TimeUnit.HOURS.toSeconds(12); static final long FIVE_MINUTES_IN_SECONDS = TimeUnit.MINUTES.toSeconds(5); + static final long ONE_DAY_IN_SECONDS = TimeUnit.DAYS.toSeconds(1); @CalledByNative private static void scheduleTask(@DownloadTaskType int taskType, @@ -69,6 +70,8 @@ 2 * FIVE_MINUTES_IN_SECONDS); scheduleTask(DownloadTaskType.CLEANUP_TASK, false, false, 0, TWELVE_HOURS_IN_SECONDS, 2 * TWELVE_HOURS_IN_SECONDS); + scheduleTask(DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK, false, false, 0, + FIVE_MINUTES_IN_SECONDS, ONE_DAY_IN_SECONDS); } private static int getTaskId(@DownloadTaskType int taskType) { @@ -77,6 +80,8 @@ return TaskIds.DOWNLOAD_SERVICE_JOB_ID; case DownloadTaskType.CLEANUP_TASK: return TaskIds.DOWNLOAD_CLEANUP_JOB_ID; + case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK: + return TaskIds.DOWNLOAD_AUTO_RESUMPTION_JOB_ID; default: assert false; return -1; @@ -85,9 +90,16 @@ private static int getRequiredNetworkType( @DownloadTaskType int taskType, boolean requiresUnmeteredNetwork) { - if (taskType != DownloadTaskType.DOWNLOAD_TASK) return TaskInfo.NETWORK_TYPE_NONE; - - return requiresUnmeteredNetwork ? TaskInfo.NETWORK_TYPE_UNMETERED - : TaskInfo.NETWORK_TYPE_ANY; + switch (taskType) { + case DownloadTaskType.CLEANUP_TASK: + return TaskInfo.NETWORK_TYPE_NONE; + case DownloadTaskType.DOWNLOAD_TASK: // intentional fall-through + case DownloadTaskType.DOWNLOAD_AUTO_RESUMPTION_TASK: + return requiresUnmeteredNetwork ? TaskInfo.NETWORK_TYPE_UNMETERED + : TaskInfo.NETWORK_TYPE_ANY; + default: + assert false; + return TaskInfo.NETWORK_TYPE_ANY; + } } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java index d1c1495..2a75f0f5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBackgroundTask.java
@@ -63,7 +63,7 @@ protected void onStartTaskWithNative( Context context, TaskParameters taskParameters, TaskFinishedCallback callback) { assert taskParameters.getTaskId() == TaskIds.EXPLORE_SITES_REFRESH_JOB_ID; - if (ExploreSitesBridge.getVariation() != ExploreSitesVariation.ENABLED) { + if (ExploreSitesBridge.isEnabled(ExploreSitesBridge.getVariation())) { cancelTask(); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java index bf3ff36..1843d1d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -83,6 +83,15 @@ return nativeGetVariation(); } + public static boolean isEnabled(@ExploreSitesVariation int variation) { + return variation == ExploreSitesVariation.ENABLED + || variation == ExploreSitesVariation.PERSONALIZED; + } + + public static boolean isExperimental(@ExploreSitesVariation int variation) { + return variation == ExploreSitesVariation.EXPERIMENT; + } + @CalledByNative static void scheduleDailyTask() { ExploreSitesBackgroundTask.schedule(false /* updateCurrent */);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java index d34d2ff..e4bcac54 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencer.java
@@ -33,7 +33,7 @@ import org.chromium.chrome.browser.util.FeatureUtilities; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.vr.VrModuleProvider; -import org.chromium.chrome.browser.webapps.WebApkActivity; +import org.chromium.chrome.browser.webapps.WebappLauncherActivity; import org.chromium.components.signin.AccountManagerFacade; import org.chromium.components.signin.ChildAccountStatus; import org.chromium.components.signin.ChromeSigninController; @@ -368,8 +368,8 @@ Intent intentToLaunchAfterFreComplete = fromIntent; String associatedAppNameForLightweightFre = null; - WebApkActivity.FreParams webApkFreParams = - WebApkActivity.slowGenerateFreParamsIfIntentIsForWebApkActivity(fromIntent); + WebappLauncherActivity.FreParams webApkFreParams = + WebappLauncherActivity.slowGenerateFreParamsIfIntentIsForWebApk(fromIntent); if (webApkFreParams != null) { intentToLaunchAfterFreComplete = webApkFreParams.getIntentToLaunchAfterFreComplete();
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 0ebe578..2c7859fb 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
@@ -302,7 +302,7 @@ if (requiresFirstRunToBeCompleted(intent) && FirstRunFlowSequencer.launch(this, intent, false /* requiresBroadcast */, - shouldPreferLightweightFre(intent))) { + false /* preferLightweightFre */)) { abortLaunch(LaunchIntentDispatcher.Action.FINISH_ACTIVITY_REMOVE_TASK); return; } @@ -401,14 +401,6 @@ } /** - * Whether to use the Lightweight First Run Experience instead of the - * non-Lightweight First Run Experience. - */ - protected boolean shouldPreferLightweightFre(Intent intent) { - return false; - } - - /** * Whether or not the Activity was started up via a valid Intent. */ protected boolean isStartedUpCorrectly(Intent intent) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java index 8d14401..5f7c0e8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManager.java
@@ -9,6 +9,7 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.ntp.ForeignSessionHelper; +import org.chromium.chrome.browser.profiles.Profile; import java.util.concurrent.TimeUnit; @@ -44,7 +45,7 @@ /** * Used to call native code that enables and disables session invalidations. */ - private final ForeignSessionHelper mForeignSessionHelper; + private final Profile mProfile; private static SessionsInvalidationManager sInstance; @@ -63,19 +64,17 @@ * * Calling this method will create the instance if it does not yet exist. */ - public static SessionsInvalidationManager get(ForeignSessionHelper foreignSessionHelper) { + public static SessionsInvalidationManager get(Profile profile) { ThreadUtils.assertOnUiThread(); if (sInstance == null) { - sInstance = new SessionsInvalidationManager( - foreignSessionHelper, new ResumableDelayedTaskRunner()); + sInstance = new SessionsInvalidationManager(profile, new ResumableDelayedTaskRunner()); } return sInstance; } @VisibleForTesting - SessionsInvalidationManager( - ForeignSessionHelper foreignSessionHelper, ResumableDelayedTaskRunner runner) { - mForeignSessionHelper = foreignSessionHelper; + SessionsInvalidationManager(Profile profile, ResumableDelayedTaskRunner runner) { + mProfile = profile; mIsSessionInvalidationsEnabled = false; mEnableSessionInvalidationsRunner = runner; ApplicationStatus.registerApplicationStateListener(this); @@ -117,7 +116,9 @@ mEnableSessionInvalidationsRunner.setRunnable(() -> { mIsSessionInvalidationsEnabled = isEnabled; - mForeignSessionHelper.setInvalidationsForSessionsEnabled(isEnabled); + ForeignSessionHelper foreignSessionHelper = new ForeignSessionHelper(mProfile); + foreignSessionHelper.setInvalidationsForSessionsEnabled(isEnabled); + foreignSessionHelper.destroy(); }, delayMs); mEnableSessionInvalidationsRunner.resume(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java index 292272b1..6911b0d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java
@@ -120,14 +120,14 @@ * Initialize this class with the given profile. * @param profile Profile that will be used for syncing. */ - ForeignSessionHelper(Profile profile) { + public ForeignSessionHelper(Profile profile) { mNativeForeignSessionHelper = nativeInit(profile); } /** * Clean up the C++ side of this class. After the call, this class instance shouldn't be used. */ - void destroy() { + public void destroy() { assert mNativeForeignSessionHelper != 0; nativeDestroy(mNativeForeignSessionHelper); mNativeForeignSessionHelper = 0;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java index 76e4bff..b8d3f713 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageLayout.java
@@ -36,7 +36,6 @@ import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection; import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge; import org.chromium.chrome.browser.explore_sites.ExploreSitesSection; -import org.chromium.chrome.browser.explore_sites.ExploreSitesVariation; import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener; @@ -191,9 +190,10 @@ mSearchBoxView = findViewById(R.id.search_box); insertSiteSectionView(); - if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) { + int variation = ExploreSitesBridge.getVariation(); + if (ExploreSitesBridge.isEnabled(variation)) { mExploreSectionView = ((ViewStub) findViewById(R.id.explore_sites_stub)).inflate(); - } else if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.EXPERIMENT) { + } else if (ExploreSitesBridge.isExperimental(variation)) { ViewStub exploreStub = findViewById(R.id.explore_sites_stub); exploreStub.setLayoutResource(R.layout.experimental_explore_sites_section); mExploreSectionView = exploreStub.inflate(); @@ -244,19 +244,12 @@ mSiteSectionViewHolder.bindDataSource(mTileGroup, tileRenderer); int variation = ExploreSitesBridge.getVariation(); - switch (variation) { - case ExploreSitesVariation.ENABLED: // fall-through - case ExploreSitesVariation.PERSONALIZED: - mExploreSection = new ExploreSitesSection(mExploreSectionView, profile, - mManager.getNavigationDelegate(), - SuggestionsConfig.getTileStyle(mUiConfig)); - break; - case ExploreSitesVariation.EXPERIMENT: - mExploreSection = new ExperimentalExploreSitesSection( - mExploreSectionView, profile, mManager.getNavigationDelegate()); - break; - case ExploreSitesVariation.DISABLED: // fall-through - default: // do nothing. + if (ExploreSitesBridge.isEnabled(variation)) { + mExploreSection = new ExploreSitesSection(mExploreSectionView, profile, + mManager.getNavigationDelegate(), SuggestionsConfig.getTileStyle(mUiConfig)); + } else if (ExploreSitesBridge.isExperimental(variation)) { + mExploreSection = new ExperimentalExploreSitesSection( + mExploreSectionView, profile, mManager.getNavigationDelegate()); } mSearchProviderLogoView = findViewById(R.id.search_provider_logo); @@ -476,7 +469,7 @@ ViewGroup.LayoutParams layoutParams = mSiteSectionView.getLayoutParams(); layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT; // If the explore sites section exists, then space it more closely. - if (ExploreSitesBridge.getVariation() == ExploreSitesVariation.ENABLED) { + if (ExploreSitesBridge.isEnabled(ExploreSitesBridge.getVariation())) { ((MarginLayoutParams) layoutParams).bottomMargin = getResources().getDimensionPixelOffset( R.dimen.tile_grid_layout_vertical_spacing);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java index 765dc829..e842949 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsManager.java
@@ -120,7 +120,7 @@ if (ChromeFeatureList.isInitialized() && ChromeFeatureList.isEnabled(ChromeFeatureList.FCM_INVALIDATIONS)) { - SessionsInvalidationManager.get(mForeignSessionHelper).onRecentTabsPageOpened(); + SessionsInvalidationManager.get(mProfile).onRecentTabsPageOpened(); } else { InvalidationController.get().onRecentTabsPageOpened(); } @@ -153,7 +153,7 @@ if (ChromeFeatureList.isInitialized() && ChromeFeatureList.isEnabled(ChromeFeatureList.FCM_INVALIDATIONS)) { - SessionsInvalidationManager.get(mForeignSessionHelper).onRecentTabsPageClosed(); + SessionsInvalidationManager.get(mProfile).onRecentTabsPageClosed(); } else { InvalidationController.get().onRecentTabsPageClosed(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java index a6879a0..a84e064 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -135,6 +135,7 @@ /** * @return True if offline pages sharing is enabled. */ + @VisibleForTesting public static boolean isPageSharingEnabled() { return nativeIsPageSharingEnabled(); } @@ -172,6 +173,39 @@ } /** + * Gets all available offline pages, returning results via the provided callback. + * + * @param callback The callback to run when the operation completes. + */ + @VisibleForTesting + public void getAllPages(final Callback<List<OfflinePageItem>> callback) { + List<OfflinePageItem> result = new ArrayList<>(); + nativeGetAllPages(mNativeOfflinePageBridge, result, callback); + } + + /** + * Gets the offline pages associated with the provided client IDs. + * + * @param clientIds Client's IDs associated with offline pages. + * @return A list of {@link OfflinePageItem} matching the provided IDs, or an empty list if none + * exist. + */ + @VisibleForTesting + public void getPagesByClientIds( + final List<ClientId> clientIds, final Callback<List<OfflinePageItem>> callback) { + String[] namespaces = new String[clientIds.size()]; + String[] ids = new String[clientIds.size()]; + + for (int i = 0; i < clientIds.size(); i++) { + namespaces[i] = clientIds.get(i).getNamespace(); + ids[i] = clientIds.get(i).getId(); + } + + List<OfflinePageItem> result = new ArrayList<>(); + nativeGetPagesByClientId(mNativeOfflinePageBridge, result, namespaces, ids, callback); + } + + /** * Gets the offline pages associated with the provided origin. * @param origin The JSON-like string of the app's package name and encrypted signature hash. * @return A list of {@link OfflinePageItem} matching the provided origin, or an empty @@ -195,6 +229,16 @@ nativeGetPagesByNamespace(mNativeOfflinePageBridge, result, namespace, callback); } + /** + * Gets all the URLs in the request queue. + * + * @return A list of {@link SavePageRequest} representing all the queued requests. + */ + @VisibleForTesting + public void getRequestsInQueue(Callback<SavePageRequest[]> callback) { + nativeGetRequestsInQueue(mNativeOfflinePageBridge, callback); + } + private static class RequestsRemovedCallback { private Callback<List<RequestRemovedResult>> mCallback; @@ -796,14 +840,23 @@ private static native boolean nativeIsPageSharingEnabled(); private static native boolean nativeCanSavePage(String url); private static native OfflinePageBridge nativeGetOfflinePageBridgeForProfile(Profile profile); - + @VisibleForTesting + native void nativeGetAllPages(long nativeOfflinePageBridge, List<OfflinePageItem> offlinePages, + final Callback<List<OfflinePageItem>> callback); private native void nativeWillCloseTab(long nativeOfflinePageBridge, WebContents webContents); - private native void nativeRemoveRequestsFromQueue( + @VisibleForTesting + native void nativeGetRequestsInQueue( + long nativeOfflinePageBridge, Callback<SavePageRequest[]> callback); + @VisibleForTesting + native void nativeRemoveRequestsFromQueue( long nativeOfflinePageBridge, long[] requestIds, RequestsRemovedCallback callback); - private native void nativeGetPageByOfflineId( + @VisibleForTesting + native void nativeGetPageByOfflineId( long nativeOfflinePageBridge, long offlineId, Callback<OfflinePageItem> callback); - + @VisibleForTesting + native void nativeGetPagesByClientId(long nativeOfflinePageBridge, List<OfflinePageItem> result, + String[] namespaces, String[] ids, Callback<List<OfflinePageItem>> callback); native void nativeGetPagesByRequestOrigin(long nativeOfflinePageBridge, List<OfflinePageItem> result, String requestOrigin, Callback<List<OfflinePageItem>> callback); @@ -818,8 +871,10 @@ @VisibleForTesting native void nativeDeletePagesByOfflineId( long nativeOfflinePageBridge, long[] offlineIds, Callback<Integer> callback); + @VisibleForTesting private native void nativePublishInternalPageByOfflineId( long nativeOfflinePageBridge, long offlineId, Callback<String> publishedCallback); + @VisibleForTesting private native void nativePublishInternalPageByGuid( long nativeOfflinePageBridge, String guid, Callback<String> publishedCallback); private native void nativeSelectPageForOnlineUrl(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java index bbaa8be6..b090be5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkActivity.java
@@ -4,8 +4,6 @@ package org.chromium.chrome.browser.webapps; -import static org.chromium.webapk.lib.common.WebApkConstants.WEBAPK_PACKAGE_PREFIX; - import android.content.Intent; import android.os.Bundle; import android.os.SystemClock; @@ -16,8 +14,6 @@ import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.metrics.WebApkSplashscreenMetrics; import org.chromium.chrome.browser.metrics.WebApkUma; -import org.chromium.chrome.browser.util.IntentUtils; -import org.chromium.webapk.lib.common.WebApkConstants; import java.util.concurrent.TimeUnit; @@ -39,48 +35,6 @@ @VisibleForTesting public static final String STARTUP_UMA_HISTOGRAM_SUFFIX = ".WebApk"; - /** WebAPK first run experience parameters. */ - public static class FreParams { - private final Intent mIntentToLaunchAfterFreComplete; - private final String mShortName; - - public FreParams(Intent intentToLaunchAfterFreComplete, String shortName) { - mIntentToLaunchAfterFreComplete = intentToLaunchAfterFreComplete; - mShortName = shortName; - } - - /** Returns the intent launch when the user completes the first run experience. */ - public Intent getIntentToLaunchAfterFreComplete() { - return mIntentToLaunchAfterFreComplete; - } - - /** Returns the WebAPK's short name. */ - public String webApkShortName() { - return mShortName; - } - } - - /** - * Generates parameters for the WebAPK first run experience for the given intent. Returns null - * if the intent does not launch a WebApkActivity. This method is slow. It makes several - * PackageManager calls. - */ - public static FreParams slowGenerateFreParamsIfIntentIsForWebApkActivity(Intent fromIntent) { - // Check for intents targeted at WebApkActivity, WebApkActivity0-9 and - // SameTaskWebApkActivity. - String targetActivityClassName = fromIntent.getComponent().getClassName(); - if (!targetActivityClassName.startsWith(WebApkActivity.class.getName()) - && !targetActivityClassName.equals(SameTaskWebApkActivity.class.getName())) { - return null; - } - - WebApkInfo info = WebApkInfo.create(fromIntent); - return (info != null) - ? new FreParams(WebappLauncherActivity.createRelaunchWebApkIntent(fromIntent, info), - info.shortName()) - : null; - } - @Override public int getActivityType() { return ActivityType.WEBAPK; @@ -103,17 +57,6 @@ } @Override - public boolean shouldPreferLightweightFre(Intent intent) { - // We cannot use getWebApkPackageName() because {@link WebappActivity#preInflationStartup()} - // may not have been called yet. - String webApkPackageName = - IntentUtils.safeGetStringExtra(intent, WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME); - - // Use the lightweight FRE for unbound WebAPKs. - return webApkPackageName != null && !webApkPackageName.startsWith(WEBAPK_PACKAGE_PREFIX); - } - - @Override public String getNativeClientPackageName() { return getWebappInfo().webApkPackageName(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java index aab0849..e039bd74 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappLauncherActivity.java
@@ -21,10 +21,12 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.ContextUtils; import org.chromium.base.Log; +import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.IntentHandler; import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.ShortcutSource; import org.chromium.chrome.browser.document.ChromeLauncherActivity; +import org.chromium.chrome.browser.firstrun.FirstRunFlowSequencer; import org.chromium.chrome.browser.metrics.LaunchMetrics; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.util.IntentUtils; @@ -54,6 +56,27 @@ private static final String TAG = "webapps"; + /** WebAPK first run experience parameters. */ + public static class FreParams { + private final Intent mIntentToLaunchAfterFreComplete; + private final String mShortName; + + public FreParams(Intent intentToLaunchAfterFreComplete, String shortName) { + mIntentToLaunchAfterFreComplete = intentToLaunchAfterFreComplete; + mShortName = shortName; + } + + /** Returns the intent launch when the user completes the first run experience. */ + public Intent getIntentToLaunchAfterFreComplete() { + return mIntentToLaunchAfterFreComplete; + } + + /** Returns the WebAPK's short name. */ + public String webApkShortName() { + return mShortName; + } + } + /** Creates intent to relaunch WebAPK. */ public static Intent createRelaunchWebApkIntent(Intent sourceIntent, WebApkInfo webApkInfo) { assert webApkInfo != null; @@ -93,6 +116,27 @@ return false; } + /** + * Generates parameters for the WebAPK first run experience for the given intent. Returns null + * if the intent does not launch either a WebappLauncherActivity or a WebApkActivity. This + * method is slow. It makes several PackageManager calls. + */ + public static FreParams slowGenerateFreParamsIfIntentIsForWebApk(Intent fromIntent) { + // Check for intents targeted at WebApkActivity, WebApkActivity0-9, + // SameTaskWebApkActivity and WebappLauncherActivity. + String targetActivityClassName = fromIntent.getComponent().getClassName(); + if (!targetActivityClassName.startsWith(WebApkActivity.class.getName()) + && !targetActivityClassName.equals(SameTaskWebApkActivity.class.getName()) + && !targetActivityClassName.equals(WebappLauncherActivity.class.getName())) { + return null; + } + + WebApkInfo info = WebApkInfo.create(fromIntent); + return (info != null) + ? new FreParams(createRelaunchWebApkIntent(fromIntent, info), info.shortName()) + : null; + } + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -107,6 +151,12 @@ return; } + if (FirstRunFlowSequencer.launch(this, intent, false /* requiresBroadcast */, + shouldPreferLightweightFre(webappInfo))) { + ApiCompatibilityUtils.finishAndRemoveTask(this); + return; + } + if (shouldLaunchWebapp(intent, webappInfo)) { launchWebapp(this, intent, webappInfo, createTimestamp); return; @@ -115,6 +165,17 @@ launchInTab(this, intent, webappInfo); } + /** + * Returns whether to prefer the Lightweight First Run Experience instead of the + * non-Lightweight First Run Experience when launching the given webapp. + */ + private static boolean shouldPreferLightweightFre(WebappInfo webappInfo) { + // Use lightweight FRE for unbound WebAPKs. + return webappInfo != null && webappInfo.webApkPackageName() != null + && !webappInfo.webApkPackageName().startsWith( + WebApkConstants.WEBAPK_PACKAGE_PREFIX); + } + private static boolean shouldLaunchWebapp(Intent intent, WebappInfo webappInfo) { // {@link WebApkInfo#create()} and {@link WebappInfo#create()} return null if the intent // does not specify required values such as the uri. @@ -354,7 +415,8 @@ } /** Tries to create WebappInfo/WebApkInfo for the intent. */ - private static WebappInfo tryCreateWebappInfo(Intent intent) { + @VisibleForTesting + static WebappInfo tryCreateWebappInfo(Intent intent) { // Builds WebApkInfo for the intent if the WebAPK package specified in the intent is a valid // WebAPK and the URL specified in the intent can be fulfilled by the WebAPK. String webApkPackage = @@ -366,6 +428,9 @@ return WebApkInfo.create(intent); } + // This is not a valid WebAPK. Modify the intent so that WebApkInfo#create() returns null. + intent.removeExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME); + Log.d(TAG, "%s is either not a WebAPK or %s is not within the WebAPK's scope", webApkPackage, url); return WebappInfo.create(intent);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 1145e05..2baeba1 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -3002,7 +3002,9 @@ No bookmarks </message> <message name="IDS_BOOKMARKS_COUNT" desc="Text describing the number of bookmarks in a bookmark folder [ICU Syntax]"> - {BOOKMARKS_COUNT, plural, =1 {%1$d bookmark} other {%1$d bookmarks}} + {BOOKMARKS_COUNT, plural, + =1 {<ph name="BOOKMARKS_COUNT_ONE">%1$d<ex>1</ex></ph> bookmark} + other {<ph name="BOOKMARKS_COUNT_MANY">%1$d<ex>8</ex></ph> bookmarks}} </message> <message name="IDS_BOOKMARK_PAGE_SAVED" desc="App-based message shown after user adds a new bookmark. [CHAR-LIMIT=32]"> Bookmarked in <ph name="PRODUCT_NAME">%1$s<ex>Chrome</ex></ph>
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index 6fe74b5..27ecc04 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -259,7 +259,9 @@ "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchQuickActionControl.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchTermControl.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java", + "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java", "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java", + "java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabTitleControl.java", "java/src/org/chromium/chrome/browser/compositor/layouts/ChromeAnimation.java", "java/src/org/chromium/chrome/browser/compositor/layouts/EmptyOverviewModeObserver.java", "java/src/org/chromium/chrome/browser/compositor/layouts/Layout.java", @@ -2541,6 +2543,7 @@ "junit/src/org/chromium/chrome/browser/webapps/WebappDataStorageTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebappDisclosureSnackbarControllerTest.java", + "junit/src/org/chromium/chrome/browser/webapps/WebappLauncherActivityTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebappInfoTest.java", "junit/src/org/chromium/chrome/browser/webapps/WebappRegistryTest.java", "junit/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetSwipeDetectorTest.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java index 2aa2ad4..b12588b 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -50,7 +50,6 @@ import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; @@ -131,7 +130,7 @@ @SmallTest @RetryOnFailure public void testLoadOfflinePagesWhenEmpty() throws Exception { - List<OfflinePageItem> offlinePages = OfflineTestUtil.getAllPages(); + List<OfflinePageItem> offlinePages = getAllPages(); Assert.assertEquals("Offline pages count incorrect.", 0, offlinePages.size()); } @@ -143,7 +142,7 @@ public void testAddOfflinePageAndLoad() throws Exception { mActivityTestRule.loadUrl(mTestPage); savePage(SavePageResult.SUCCESS, mTestPage); - List<OfflinePageItem> allPages = OfflineTestUtil.getAllPages(); + List<OfflinePageItem> allPages = getAllPages(); OfflinePageItem offlinePage = allPages.get(0); Assert.assertEquals("Offline pages count incorrect.", 1, allPages.size()); Assert.assertEquals("Offline page item url incorrect.", mTestPage, offlinePage.getUrl()); @@ -155,11 +154,10 @@ public void testGetPageByBookmarkId() throws Exception { mActivityTestRule.loadUrl(mTestPage); savePage(SavePageResult.SUCCESS, mTestPage); - OfflinePageItem offlinePage = OfflineTestUtil.getPageByClientId(TEST_CLIENT_ID); + OfflinePageItem offlinePage = getPageByClientId(TEST_CLIENT_ID); Assert.assertEquals("Offline page item url incorrect.", mTestPage, offlinePage.getUrl()); Assert.assertNull("Offline page is not supposed to exist", - OfflineTestUtil.getPageByClientId( - new ClientId(OfflinePageBridge.BOOKMARK_NAMESPACE, "-42"))); + getPageByClientId(new ClientId(OfflinePageBridge.BOOKMARK_NAMESPACE, "-42"))); } @Test @@ -172,10 +170,10 @@ mActivityTestRule.loadUrl(mTestPage); savePage(SavePageResult.SUCCESS, mTestPage); Assert.assertNotNull("Offline page should be available, but it is not.", - OfflineTestUtil.getPageByClientId(TEST_CLIENT_ID)); + getPageByClientId(TEST_CLIENT_ID)); deletePage(TEST_CLIENT_ID, DeletePageResult.SUCCESS); Assert.assertNull("Offline page should be gone, but it is available.", - OfflineTestUtil.getPageByClientId(TEST_CLIENT_ID)); + getPageByClientId(TEST_CLIENT_ID)); } @Test @@ -200,7 +198,7 @@ String url = "https://www.google.com/"; String namespace = "custom_tabs"; savePageLater(url, namespace); - SavePageRequest[] requests = OfflineTestUtil.getRequestsInQueue(); + SavePageRequest[] requests = getRequestsInQueue(); Assert.assertEquals(1, requests.length); Assert.assertEquals(namespace, requests[0].getClientId().getNamespace()); Assert.assertEquals(url, requests[0].getUrl()); @@ -208,7 +206,7 @@ String url2 = "https://mail.google.com/"; String namespace2 = "last_n"; savePageLater(url2, namespace2); - requests = OfflineTestUtil.getRequestsInQueue(); + requests = getRequestsInQueue(); Assert.assertEquals(2, requests.length); HashSet<String> expectedUrls = new HashSet<>(); @@ -247,7 +245,7 @@ String namespace2 = "last_n"; savePageLater(url2, namespace2); - SavePageRequest[] requests = OfflineTestUtil.getRequestsInQueue(); + SavePageRequest[] requests = getRequestsInQueue(); Assert.assertEquals(2, requests.length); List<Long> requestsToRemove = new ArrayList<>(); @@ -257,7 +255,7 @@ removeRequestsFromQueue(requestsToRemove); Assert.assertEquals(requests[1].getRequestId(), removed.get(0).getRequestId()); Assert.assertEquals(UpdateRequestResult.SUCCESS, removed.get(0).getUpdateRequestResult()); - SavePageRequest[] remaining = OfflineTestUtil.getRequestsInQueue(); + SavePageRequest[] remaining = getRequestsInQueue(); Assert.assertEquals(1, remaining.length); Assert.assertEquals(requests[0].getRequestId(), remaining[0].getRequestId()); @@ -373,7 +371,7 @@ Assert.assertTrue("Semaphore acquire failed. Timed out.", semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - List<OfflinePageItem> pages = OfflineTestUtil.getAllPages(); + List<OfflinePageItem> pages = getAllPages(); Assert.assertEquals(originString, pages.get(0).getRequestOrigin()); } @@ -406,7 +404,7 @@ Assert.assertTrue("Semaphore acquire failed. Timed out.", semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); - List<OfflinePageItem> pages = OfflineTestUtil.getAllPages(); + List<OfflinePageItem> pages = getAllPages(); Assert.assertEquals(originString, pages.get(0).getRequestOrigin()); } @@ -416,7 +414,7 @@ public void testSavePageNoOrigin() throws Exception { mActivityTestRule.loadUrl(mTestPage); savePage(SavePageResult.SUCCESS, mTestPage); - List<OfflinePageItem> pages = OfflineTestUtil.getAllPages(); + List<OfflinePageItem> pages = getAllPages(); Assert.assertEquals("", pages.get(0).getRequestOrigin()); } @@ -428,7 +426,7 @@ public void testGetLoadUrlParamsForOpeningMhtmlFileUrl() throws Exception { mActivityTestRule.loadUrl(mTestPage); savePage(SavePageResult.SUCCESS, mTestPage); - List<OfflinePageItem> allPages = OfflineTestUtil.getAllPages(); + List<OfflinePageItem> allPages = getAllPages(); Assert.assertEquals(1, allPages.size()); OfflinePageItem offlinePage = allPages.get(0); File archiveFile = new File(offlinePage.getFilePath()); @@ -558,6 +556,25 @@ Assert.assertEquals("Delete result incorrect.", expectedResult, deletePageResultRef.get()); } + private List<OfflinePageItem> getAllPages() throws InterruptedException { + final List<OfflinePageItem> result = new ArrayList<OfflinePageItem>(); + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.getAllPages(new Callback<List<OfflinePageItem>>() { + @Override + public void onResult(List<OfflinePageItem> pages) { + result.addAll(pages); + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return result; + } + private List<OfflinePageItem> getPagesByNamespace(final String namespace) throws InterruptedException { final List<OfflinePageItem> result = new ArrayList<OfflinePageItem>(); @@ -588,10 +605,49 @@ }); } + private OfflinePageItem getPageByClientId(ClientId clientId) throws InterruptedException { + final OfflinePageItem[] result = {null}; + final Semaphore semaphore = new Semaphore(0); + final List<ClientId> clientIdList = new ArrayList<>(); + clientIdList.add(clientId); + + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.getPagesByClientIds( + clientIdList, new Callback<List<OfflinePageItem>>() { + @Override + public void onResult(List<OfflinePageItem> items) { + if (!items.isEmpty()) { + result[0] = items.get(0); + } + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return result[0]; + } + private Set<String> getUrlsExistOfflineFromSet(final Set<String> query) - throws InterruptedException, TimeoutException { + throws InterruptedException { final Set<String> result = new HashSet<>(); - final List<OfflinePageItem> pages = OfflineTestUtil.getAllPages(); + final List<OfflinePageItem> pages = new ArrayList<>(); + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.getAllPages(new Callback<List<OfflinePageItem>>() { + @Override + public void onResult(List<OfflinePageItem> offlinePages) { + pages.addAll(offlinePages); + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); for (String url : query) { for (OfflinePageItem page : pages) { if (url.equals(page.getUrl())) { @@ -623,6 +679,25 @@ Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } + private SavePageRequest[] getRequestsInQueue() throws InterruptedException { + final AtomicReference<SavePageRequest[]> ref = new AtomicReference<>(); + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.getRequestsInQueue(new Callback<SavePageRequest[]>() { + @Override + public void onResult(SavePageRequest[] requestsInQueue) { + ref.set(requestsInQueue); + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return ref.get(); + } + private List<OfflinePageBridge.RequestRemovedResult> removeRequestsFromQueue( final List<Long> requestsToRemove) throws InterruptedException { final AtomicReference<List<OfflinePageBridge.RequestRemovedResult>> ref =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java index 49985c9..4d517b2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageRequestTest.java
@@ -18,7 +18,9 @@ import org.chromium.base.test.util.DisabledTest; import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.SavePageCallback; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -48,6 +50,7 @@ @Before public void setUp() throws Exception { mActivityTestRule.startMainActivityOnBlankPage(); + final Semaphore semaphore = new Semaphore(0); ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { @@ -55,9 +58,23 @@ NetworkChangeNotifier.init(); } NetworkChangeNotifier.forceConnectivityState(true); + + Profile profile = Profile.getLastUsedProfile(); + mOfflinePageBridge = OfflinePageBridge.getForProfile(profile); + if (mOfflinePageBridge.isOfflinePageModelLoaded()) { + semaphore.release(); + } else { + mOfflinePageBridge.addObserver(new OfflinePageModelObserver() { + @Override + public void offlinePageModelLoaded() { + semaphore.release(); + mOfflinePageBridge.removeObserver(this); + } + }); + } } }); - mOfflinePageBridge = OfflineTestUtil.getOfflinePageBridge(); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java index 1aa75406..ed0c917c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageSavePageLaterEvaluationTest.java
@@ -405,10 +405,24 @@ /** * Get saved offline pages and align them with the metadata we got from testing. */ - private void loadSavedPages() throws TimeoutException, InterruptedException { - for (OfflinePageItem page : OfflineTestUtil.getAllPages()) { - mRequestMetadata.get(page.getOfflineId()).mPage = page; - } + private void loadSavedPages() throws InterruptedException { + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mBridge.getAllPages(new Callback<List<OfflinePageItem>>() { + @Override + public void onResult(List<OfflinePageItem> pages) { + for (OfflinePageItem page : pages) { + mRequestMetadata.get(page.getOfflineId()).mPage = page; + } + semaphore.release(); + } + }); + } + }); + checkTrue(semaphore.tryAcquire(GET_PAGES_TIMEOUT_MS, TimeUnit.MILLISECONDS), + "Timed out when getting all offline pages"); } private boolean copyToShareableLocation(File src, File dst) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java deleted file mode 100644 index 8e949e6..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflineTestUtil.java +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.offlinepages; - -import android.support.annotation.Nullable; - -import org.junit.Assert; - -import org.chromium.base.Callback; -import org.chromium.base.ThreadUtils; -import org.chromium.base.annotations.JNINamespace; -import org.chromium.base.test.util.CallbackHelper; -import org.chromium.chrome.browser.download.items.OfflineContentAggregatorFactory; -import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver; -import org.chromium.chrome.browser.profiles.Profile; -import org.chromium.components.offline_items_collection.OfflineItem; - -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicReference; - -/** Test utility functions for OfflinePages. */ -@JNINamespace("offline_pages") -public class OfflineTestUtil { - // Gets all the URLs in the request queue. - public static SavePageRequest[] getRequestsInQueue() - throws TimeoutException, InterruptedException { - final AtomicReference<SavePageRequest[]> result = new AtomicReference<>(); - final CallbackHelper callbackHelper = new CallbackHelper(); - ThreadUtils.runOnUiThreadBlocking(() -> { - nativeGetRequestsInQueue((SavePageRequest[] requests) -> { - result.set(requests); - callbackHelper.notifyCalled(); - }); - }); - callbackHelper.waitForCallback(0); - return result.get(); - } - - // Gets all available offline pages. - public static List<OfflinePageItem> getAllPages() - throws TimeoutException, InterruptedException { - final AtomicReference<List<OfflinePageItem>> result = - new AtomicReference<List<OfflinePageItem>>(); - final CallbackHelper callbackHelper = new CallbackHelper(); - ThreadUtils.runOnUiThreadBlocking(() -> { - nativeGetAllPages(new ArrayList<OfflinePageItem>(), (List<OfflinePageItem> items) -> { - result.set(items); - callbackHelper.notifyCalled(); - }); - }); - callbackHelper.waitForCallback(0); - return result.get(); - } - - // Returns the OfflinePageItem with the given clientId, or null if one doesn't exist. - public static @Nullable OfflinePageItem getPageByClientId(ClientId clientId) - throws TimeoutException, InterruptedException { - ArrayList<OfflinePageItem> result = new ArrayList<OfflinePageItem>(); - for (OfflinePageItem item : getAllPages()) { - if (item.getClientId().equals(clientId)) { - return item; - } - } - return null; - } - - // Returns all OfflineItems provided by the OfflineContentProvider. - public static List<OfflineItem> getOfflineItems() - throws TimeoutException, InterruptedException { - CallbackHelper finished = new CallbackHelper(); - final AtomicReference<ArrayList<OfflineItem>> result = - new AtomicReference<ArrayList<OfflineItem>>(); - ThreadUtils.runOnUiThreadBlocking(() -> { - OfflineContentAggregatorFactory - .forProfile(Profile.getLastUsedProfile().getOriginalProfile()) - .getAllItems(items -> { - result.set(items); - finished.notifyCalled(); - }); - }); - finished.waitForCallback(0); - return result.get(); - } - - // Waits for the offline model to initialize and returns an OfflinePageBridge. - public static OfflinePageBridge getOfflinePageBridge() - throws TimeoutException, InterruptedException { - final CallbackHelper ready = new CallbackHelper(); - final AtomicReference<OfflinePageBridge> result = new AtomicReference<OfflinePageBridge>(); - ThreadUtils.runOnUiThread(() -> { - OfflinePageBridge bridge = - OfflinePageBridge.getForProfile(Profile.getLastUsedProfile()); - if (bridge == null || bridge.isOfflinePageModelLoaded()) { - result.set(bridge); - ready.notifyCalled(); - return; - } - bridge.addObserver(new OfflinePageModelObserver() { - @Override - public void offlinePageModelLoaded() { - result.set(bridge); - ready.notifyCalled(); - bridge.removeObserver(this); - } - }); - }); - ready.waitForCallback(0); - Assert.assertTrue(result.get() != null); - return result.get(); - } - - private static native void nativeGetRequestsInQueue(Callback<SavePageRequest[]> callback); - private static native void nativeGetAllPages( - List<OfflinePageItem> offlinePages, final Callback<List<OfflinePageItem>> callback); -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RecentTabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RecentTabsTest.java index 313f225..61cf5ffb 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RecentTabsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/RecentTabsTest.java
@@ -14,21 +14,26 @@ import org.junit.Test; import org.junit.runner.RunWith; +import org.chromium.base.Callback; import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver; +import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tabmodel.TabModel; import org.chromium.chrome.browser.tabmodel.TabModelSelector; import org.chromium.chrome.browser.tabmodel.TabModelUtils; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; import org.chromium.chrome.test.ChromeTabbedActivityTestRule; -import org.chromium.content_public.browser.test.util.CriteriaHelper; import org.chromium.net.NetworkChangeNotifier; import org.chromium.net.test.EmbeddedTestServer; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.Callable; -import java.util.concurrent.TimeoutException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; /** Integration tests for the Last 1 feature of Offline Pages. */ @RunWith(ChromeJUnit4ClassRunner.class) @@ -44,6 +49,34 @@ private EmbeddedTestServer mTestServer; private String mTestPage; + private void initializeBridgeForProfile(final boolean incognitoProfile) + throws InterruptedException { + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + Profile profile = Profile.getLastUsedProfile(); + if (incognitoProfile) { + profile = profile.getOffTheRecordProfile(); + } + // Ensure we start in an offline state. + mOfflinePageBridge = OfflinePageBridge.getForProfile(profile); + if (mOfflinePageBridge == null || mOfflinePageBridge.isOfflinePageModelLoaded()) { + semaphore.release(); + return; + } + mOfflinePageBridge.addObserver(new OfflinePageModelObserver() { + @Override + public void offlinePageModelLoaded() { + semaphore.release(); + mOfflinePageBridge.removeObserver(this); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + @Before public void setUp() throws Exception { mActivityTestRule.startMainActivityOnBlankPage(); @@ -58,7 +91,8 @@ } }); - mOfflinePageBridge = OfflineTestUtil.getOfflinePageBridge(); + initializeBridgeForProfile(false); + mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext()); mTestPage = mTestServer.getURL(TEST_PAGE); } @@ -79,7 +113,7 @@ new ClientId(OfflinePageBridge.LAST_N_NAMESPACE, Integer.toString(tab.getId())); // The tab should be foreground and so no snapshot should exist. - Assert.assertNull(OfflineTestUtil.getPageByClientId(firstTabClientId)); + Assert.assertNull(getPageByClientId(firstTabClientId)); // Note, that switching to a new tab must occur after the SnapshotController believes the // page quality is good enough. With the debug flag, the delay after DomContentLoaded is 0 @@ -110,7 +144,7 @@ TabModelSelector tabModelSelector = tab.getTabModelSelector(); Assert.assertEquals(tabModelSelector.getCurrentTab(), tab); Assert.assertFalse(tab.isHidden()); - Assert.assertNull(OfflineTestUtil.getPageByClientId(firstTabClientId)); + Assert.assertNull(getPageByClientId(firstTabClientId)); // The tab model is expected to support pending closures. final TabModel tabModel = tabModelSelector.getModelForTabId(tab.getId()); @@ -129,7 +163,7 @@ // Wait a bit and checks that no snapshot was created. Thread.sleep(100); // Note: Flakiness potential here. - Assert.assertNull(OfflineTestUtil.getPageByClientId(firstTabClientId)); + Assert.assertNull(getPageByClientId(firstTabClientId)); // Undo the closure and make sure the tab is again the current one on foreground. ThreadUtils.runOnUiThreadBlocking(new Runnable() { @@ -151,9 +185,49 @@ waitForPageWithClientId(firstTabClientId); } - private void waitForPageWithClientId(final ClientId clientId) - throws TimeoutException, InterruptedException { - CriteriaHelper.pollInstrumentationThread( - () -> { return OfflineTestUtil.getPageByClientId(clientId) != null; }); + private void waitForPageWithClientId(final ClientId clientId) throws InterruptedException { + if (getPageByClientId(clientId) != null) return; + + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.addObserver(new OfflinePageModelObserver() { + @Override + public void offlinePageAdded(OfflinePageItem newPage) { + if (newPage.getClientId().equals(clientId)) { + mOfflinePageBridge.removeObserver(this); + semaphore.release(); + } + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + } + + private OfflinePageItem getPageByClientId(ClientId clientId) throws InterruptedException { + final OfflinePageItem[] result = {null}; + final Semaphore semaphore = new Semaphore(0); + final List<ClientId> clientIdList = new ArrayList<>(); + clientIdList.add(clientId); + + ThreadUtils.runOnUiThread(new Runnable() { + @Override + public void run() { + mOfflinePageBridge.getPagesByClientIds( + clientIdList, new Callback<List<OfflinePageItem>>() { + @Override + public void onResult(List<OfflinePageItem> items) { + if (!items.isEmpty()) { + result[0] = items.get(0); + } + semaphore.release(); + } + }); + } + }); + Assert.assertTrue(semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + return result[0]; } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java index 4f2097ef..4432e51f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchFeedFlowTest.java
@@ -34,7 +34,6 @@ import org.chromium.chrome.browser.feed.TestNetworkClient; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.offlinepages.OfflinePageItem; -import org.chromium.chrome.browser.offlinepages.OfflineTestUtil; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.test.ChromeActivityTestRule; @@ -203,12 +202,20 @@ } private OfflineItem findItemByUrl(String url) throws InterruptedException, TimeoutException { - for (OfflineItem item : OfflineTestUtil.getOfflineItems()) { - if (item.pageUrl.equals(URL1)) { - return item; - } - } - return null; + CallbackHelper finished = new CallbackHelper(); + final AtomicReference<OfflineItem> result = new AtomicReference<OfflineItem>(); + ThreadUtils.runOnUiThreadBlocking(() -> { + offlineContentProvider().getAllItems(items -> { + for (OfflineItem item : items) { + if (item.pageUrl.equals(URL1)) { + result.set(item); + } + } + finished.notifyCalled(); + }); + }); + finished.waitForCallback(0); + return result.get(); } private Bitmap findVisuals(ContentId id) throws InterruptedException, TimeoutException {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java index e33017af..ca98287 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunIntegrationUnitTest.java
@@ -12,7 +12,6 @@ import android.os.Bundle; import android.os.UserManager; import android.support.customtabs.CustomTabsIntent; -import android.text.TextUtils; import org.junit.Assert; import org.junit.Before; @@ -33,9 +32,6 @@ import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.document.ChromeLauncherActivity; import org.chromium.chrome.browser.searchwidget.SearchActivity; -import org.chromium.chrome.browser.webapps.SameTaskWebApkActivity; -import org.chromium.chrome.browser.webapps.WebApkActivity; -import org.chromium.chrome.browser.webapps.WebApkActivity0; import org.chromium.chrome.browser.webapps.WebappLauncherActivity; import org.chromium.webapk.lib.client.WebApkValidator; import org.chromium.webapk.lib.common.WebApkConstants; @@ -76,11 +72,6 @@ return false; } - /** Checks whether the intent has the provided action. */ - private boolean checkIntentHasAction(Intent intent, String action) { - return intent != null && TextUtils.equals(intent.getAction(), action); - } - /** * Checks that intent is either for {@link FirstRunActivity} or * {@link TabbedModeFirstRunActivity}. @@ -187,15 +178,9 @@ Robolectric.buildActivity(WebappLauncherActivity.class, intent).create(); Intent launchedIntent = mShadowApplication.getNextStartedActivity(); - while (checkIntentHasAction(launchedIntent, WebApkConstants.ACTION_SHOW_SPLASH) - || checkIntentComponentClassOneOf(launchedIntent, - new Class[] {WebApkActivity.class, WebApkActivity0.class, - SameTaskWebApkActivity.class})) { - if (launchedIntent.getComponent() != null) { - buildActivityWithClassNameFromIntent(launchedIntent); - } - // Get next intent even if we did not build an activity to deal with the case of - // several activities having been started simultaneously. + while (checkIntentComponentClassOneOf( + launchedIntent, new Class[] {WebappLauncherActivity.class})) { + buildActivityWithClassNameFromIntent(launchedIntent); launchedIntent = mShadowApplication.getNextStartedActivity(); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManagerTest.java index 30bc041..c54b7ee 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManagerTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/invalidation/SessionsInvalidationManagerTest.java
@@ -23,8 +23,8 @@ import org.chromium.base.ApplicationStatus; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.chrome.browser.ntp.ForeignSessionHelper; +import org.chromium.chrome.browser.profiles.Profile; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -37,6 +37,9 @@ private ResumableDelayedTaskRunner mResumableDelayedTaskRunner; @Mock + private Profile mProfile; + + @Mock private ForeignSessionHelper mForeignSessionHelper; private Activity mActivity; @@ -56,7 +59,7 @@ final AtomicBoolean listenerCallbackCalled = new AtomicBoolean(); // Create instance. - new SessionsInvalidationManager(mForeignSessionHelper, mResumableDelayedTaskRunner) { + new SessionsInvalidationManager(mProfile, mResumableDelayedTaskRunner) { @Override public void onApplicationStateChange(int newState) { listenerCallbackCalled.set(true); @@ -72,46 +75,12 @@ } /** - * Test that sessions invalidations state with opening/closing recent pages. - */ - @Test - public void testIsSessionInvalidationsEnabled() { - SessionsInvalidationManager manager = - SessionsInvalidationManager.get(mForeignSessionHelper); - assertFalse(manager.isSessionInvalidationsEnabled()); - - manager.onRecentTabsPageOpened(); - Robolectric.getForegroundThreadScheduler().advanceBy( - SessionsInvalidationManager.REGISTER_FOR_SESSION_SYNC_INVALIDATIONS_DELAY_MS, - TimeUnit.MILLISECONDS); - // 1 recent tabs page. - assertTrue(manager.isSessionInvalidationsEnabled()); - verify(mForeignSessionHelper).setInvalidationsForSessionsEnabled(/*enabled=*/true); - - manager.onRecentTabsPageOpened(); - // 2 recent tabs pages. - assertTrue(manager.isSessionInvalidationsEnabled()); - - manager.onRecentTabsPageClosed(); - // 1 recent tabs page. - assertTrue(manager.isSessionInvalidationsEnabled()); - - manager.onRecentTabsPageClosed(); - Robolectric.getForegroundThreadScheduler().advanceBy( - SessionsInvalidationManager.UNREGISTER_FOR_SESSION_SYNC_INVALIDATIONS_DELAY_MS, - TimeUnit.MILLISECONDS); - // 0 recent tabs page. - assertFalse(manager.isSessionInvalidationsEnabled()); - verify(mForeignSessionHelper).setInvalidationsForSessionsEnabled(/*enabled=*/false); - } - - /** * Test that timer pauses when the application goes to the background. */ @Test public void testTimerPausesWhenTheApplicationPauses() { SessionsInvalidationManager manager = - new SessionsInvalidationManager(mForeignSessionHelper, mResumableDelayedTaskRunner); + new SessionsInvalidationManager(mProfile, mResumableDelayedTaskRunner); manager.onApplicationStateChange(ApplicationState.HAS_RUNNING_ACTIVITIES); verify(mResumableDelayedTaskRunner).resume();
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java index 3840dd8..5c7060a2 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
@@ -118,6 +118,80 @@ } /** + * Tests OfflinePageBridge#GetAllPages() callback when there are no pages. + */ + @Test + @Feature({"OfflinePages"}) + public void testGetAllPages_listOfPagesEmpty() { + final int itemCount = 0; + + answerNativeGetAllPages(itemCount); + Callback<List<OfflinePageItem>> callback = createMultipleItemCallback(itemCount); + mBridge.getAllPages(callback); + + List<OfflinePageItem> itemList = new ArrayList<OfflinePageItem>(); + verify(callback, times(1)).onResult(itemList); + } + + /** + * Tests OfflinePageBridge#GetAllPages() callback when there are pages. + */ + @Test + @Feature({"OfflinePages"}) + public void testGetAllPages_listOfPagesNonEmpty() { + final int itemCount = 2; + + answerNativeGetAllPages(itemCount); + Callback<List<OfflinePageItem>> callback = createMultipleItemCallback(itemCount); + mBridge.getAllPages(callback); + + List<OfflinePageItem> itemList = new ArrayList<OfflinePageItem>(); + itemList.add(TEST_OFFLINE_PAGE_ITEM); + itemList.add(TEST_OFFLINE_PAGE_ITEM); + verify(callback, times(1)).onResult(itemList); + } + + /** + * Tests OfflinePageBridge#GetPagesByClientIds() callback when there are no pages. + */ + @Test + @Feature({"OfflinePages"}) + public void testGetPagesByClientIds_listOfClientIdsEmpty() { + final int itemCount = 0; + + answerGetPagesByClientIds(itemCount); + Callback<List<OfflinePageItem>> callback = createMultipleItemCallback(itemCount); + ClientId secondClientId = new ClientId(TEST_NAMESPACE, "id number two"); + List<ClientId> list = new ArrayList<>(); + mBridge.getPagesByClientIds(list, callback); + + List<OfflinePageItem> itemList = new ArrayList<OfflinePageItem>(); + verify(callback, times(1)).onResult(itemList); + } + + /** + * Tests OfflinePageBridge#GetPagesByClientIds() callback when there are pages. + */ + @Test + @Feature({"OfflinePages"}) + public void testGetPagesByClientIds() { + final int itemCount = 2; + + answerGetPagesByClientIds(itemCount); + Callback<List<OfflinePageItem>> callback = createMultipleItemCallback(itemCount); + ClientId secondClientId = new ClientId(TEST_NAMESPACE, "id number two"); + List<ClientId> list = new ArrayList<>(); + list.add(TEST_CLIENT_ID); + list.add(secondClientId); + mBridge.getPagesByClientIds(list, callback); + + List<OfflinePageItem> itemList = new ArrayList<OfflinePageItem>(); + itemList.add(TEST_OFFLINE_PAGE_ITEM); + itemList.add(TEST_OFFLINE_PAGE_ITEM); + verify(callback, times(1)).onResult(itemList); + } + + /** * Tests OfflinePageBridge#DeletePagesByClientIds() callback when there are no pages. */ @Test @@ -222,6 +296,50 @@ }); } + private void answerNativeGetAllPages(final int itemCount) { + Answer<Void> answer = new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) { + List<OfflinePageItem> result = mResultArgument.getValue(); + for (int i = 0; i < itemCount; i++) { + result.add(TEST_OFFLINE_PAGE_ITEM); + } + + mCallbackArgument.getValue().onResult(result); + + return null; + } + }; + doAnswer(answer).when(mBridge).nativeGetAllPages( + anyLong(), mResultArgument.capture(), mCallbackArgument.capture()); + } + + private void answerGetPagesByClientIds(final int itemCount) { + Answer<Void> answer = new Answer<Void>() { + @Override + public Void answer(InvocationOnMock invocation) { + List<OfflinePageItem> result = mResultArgument.getValue(); + String[] namespaces = mNamespacesArgument.getValue(); + String[] ids = mIdsArgument.getValue(); + + assertEquals(namespaces.length, itemCount); + assertEquals(ids.length, itemCount); + + for (int i = 0; i < itemCount; i++) { + result.add(TEST_OFFLINE_PAGE_ITEM); + } + + mCallbackArgument.getValue().onResult(result); + + return null; + } + }; + + doAnswer(answer).when(mBridge).nativeGetPagesByClientId(anyLong(), + mResultArgument.capture(), mNamespacesArgument.capture(), mIdsArgument.capture(), + mCallbackArgument.capture()); + } + private void answerDeletePagesByOfflineIds(final int itemCount) { Answer<Void> answer = new Answer<Void>() { @Override
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappLauncherActivityTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappLauncherActivityTest.java new file mode 100644 index 0000000..5316235 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/webapps/WebappLauncherActivityTest.java
@@ -0,0 +1,48 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.webapps; + +import android.content.Intent; +import android.os.Bundle; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.chrome.browser.ShortcutHelper; +import org.chromium.webapk.lib.common.WebApkConstants; +import org.chromium.webapk.lib.common.WebApkMetaDataKeys; +import org.chromium.webapk.test.WebApkTestHelper; + +/** JUnit test for WebappLauncherActivity. */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class WebappLauncherActivityTest { + private static final String WEBAPK_PACKAGE_NAME = "org.chromium.webapk.test_package"; + private static final String START_URL = "https://www.google.com/scope/a_is_for_apple"; + + /** + * Test that WebappLauncherActivity#tryCreateWebappInfo() modifies the passed-in intent so + * that WebApkInfo#create() returns null if the intent does not refer to a valid + * WebAPK. + */ + @Test + public void tryCreateWebappInfoAltersIntentIfNotValidWebApk() { + Bundle bundle = new Bundle(); + bundle.putString(WebApkMetaDataKeys.START_URL, START_URL); + WebApkTestHelper.registerWebApkWithMetaData( + WEBAPK_PACKAGE_NAME, bundle, null /* shareTargetMetaData */); + + Intent intent = new Intent(); + intent.putExtra(WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME, WEBAPK_PACKAGE_NAME); + intent.putExtra(ShortcutHelper.EXTRA_URL, START_URL); + + Assert.assertNotNull(WebApkInfo.create(intent)); + Assert.assertNull(WebappLauncherActivity.tryCreateWebappInfo(intent)); + Assert.assertNull(WebApkInfo.create(intent)); + } +}
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 508ebff..a75f656d 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -4385,18 +4385,18 @@ Items not listed here will also be removed, if needed. Learn more about <a href="<ph name="URL">$1<ex>https://www.google.com/chrome/browser/privacy/whitepaper.html#unwantedsoftware</ex></ph>">unwanted software protection</a> in the Chrome privacy white paper. </message> <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_EXTENSIONS" desc="Introduces a bullet list containing the names of extensions to be removed by Chrome."> - Extensions: + Extensions to be removed: </message> <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_EXTENSION_UNKNOWN" desc="Text for a list item among a list of extensions, where we could not determine the name of the extension being cleaned up."> Unknown extension with ID <ph name="EXTENSION_ID">$1<ex>exampleextensionababababcdcdcdcd</ex></ph> </message> - <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_FILES_AND_PROGRAMS" desc="Introduces a bullet list containing the names of files and programs to be removed by Chrome."> - Files and programs: + <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_FILES_AND_PROGRAMS" desc="Introduces a bullet list containing the names of files and programs to be quarantined by Chrome (i.e. removed from the original location, moved and archived in the Quarantine folder)."> + Files and programs to be quarantined: </message> - <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_ITEMS_TO_BE_REMOVED" desc="Label for an expansion arrow. On expansion, the screen displays a list of files and programs that Chrome will remove. Placeholder can be 2 or more items."> + <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_ITEMS_TO_BE_REMOVED" desc="Label for an expansion arrow. On expansion, the screen displays a list of files and programs that Chrome will remove or quarantine. Placeholder can be 2 or more items."> {NUM_ITEMS, plural, - =1 {1 item to be removed} - other {# items to be removed}} + =1 {1 item} + other {# items}} </message> <message name="IDS_SETTINGS_RESET_CLEANUP_DETAILS_REGISTRY_ENTRIES" desc="Introduces a bullet list containing the names of registry entries to be removed/changed by Chrome."> Registry entries to be removed or changed:
diff --git a/chrome/app/theme/default_100_percent/common/alert_small.png b/chrome/app/theme/default_100_percent/common/alert_small.png deleted file mode 100644 index 342b2dda..0000000 --- a/chrome/app/theme/default_100_percent/common/alert_small.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/app_list_v1_overlay.png b/chrome/app/theme/default_100_percent/common/app_list_v1_overlay.png deleted file mode 100644 index 8476557..0000000 --- a/chrome/app/theme/default_100_percent/common/app_list_v1_overlay.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/cookies.png b/chrome/app/theme/default_100_percent/common/cookies.png deleted file mode 100644 index 7ebf43f..0000000 --- a/chrome/app/theme/default_100_percent/common/cookies.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/supervised_user_placeholder.png b/chrome/app/theme/default_100_percent/common/supervised_user_placeholder.png deleted file mode 100644 index 7a03286..0000000 --- a/chrome/app/theme/default_100_percent/common/supervised_user_placeholder.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/alert_small.png b/chrome/app/theme/default_200_percent/common/alert_small.png deleted file mode 100644 index cad7944..0000000 --- a/chrome/app/theme/default_200_percent/common/alert_small.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/app_list_v1_overlay.png b/chrome/app/theme/default_200_percent/common/app_list_v1_overlay.png deleted file mode 100644 index 9a6f805..0000000 --- a/chrome/app/theme/default_200_percent/common/app_list_v1_overlay.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/cookies.png b/chrome/app/theme/default_200_percent/common/cookies.png deleted file mode 100644 index 467b1ca..0000000 --- a/chrome/app/theme/default_200_percent/common/cookies.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/supervised_user_placeholder.png b/chrome/app/theme/default_200_percent/common/supervised_user_placeholder.png deleted file mode 100644 index d0036dcb..0000000 --- a/chrome/app/theme/default_200_percent/common/supervised_user_placeholder.png +++ /dev/null Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 5b66242e..872f38af 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd
@@ -25,9 +25,6 @@ <!-- KEEP THESE IN ALPHABETICAL ORDER! DO NOT ADD TO RANDOM PLACES JUST BECAUSE YOUR RESOURCES ARE FUNCTIONALLY RELATED OR FALL UNDER THE SAME CONDITIONALS. --> - <if expr="enable_app_list"> - <structure type="chrome_scaled_image" name="IDR_APP_LIST_TAB_OVERLAY" file="common/app_list_v1_overlay.png" /> - </if> <if expr="toolkit_views and not is_macosx"> <structure type="chrome_scaled_image" name="IDR_APP_WINDOW_CLOSE" file="common/app_window_close.png" /> <structure type="chrome_scaled_image" name="IDR_APP_WINDOW_CLOSE_H" file="common/app_window_close_hover.png" /> @@ -90,7 +87,6 @@ <if expr="is_win"> <structure type="chrome_scaled_image" name="IDR_CONFLICT_FAVICON" file="common/favicon_conflicts.png" /> </if> - <structure type="chrome_scaled_image" name="IDR_COOKIES" file="common/cookies.png" /> <structure type="chrome_scaled_image" name="IDR_COOKIE_STORAGE_ICON" file="common/cookie_storage.png" /> <if expr="chromeos"> <structure type="chrome_scaled_image" name="IDR_DEVICE_DISABLED" file="cros/device_disabled.png" /> @@ -265,7 +261,6 @@ <structure type="chrome_scaled_image" name="IDR_LOGO_AVATAR_CIRCLE_BLUE_COLOR" file="cros/logo_avatar_circle_blue_color.png" /> <structure type="chrome_scaled_image" name="IDR_LOGO_GOOGLE_COLOR_90" file="cros/logo_google_color_90.png" /> </if> - <structure type="chrome_scaled_image" name="IDR_SUPERVISED_USER_PLACEHOLDER" file="common/supervised_user_placeholder.png" /> <if expr="is_macosx"> <structure type="chrome_scaled_image" name="IDR_SWIPE_BACK" file="mac/back_large.png" /> <structure type="chrome_scaled_image" name="IDR_SWIPE_FORWARD" file="mac/forward_large.png" /> @@ -324,7 +319,6 @@ <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_CAPTURE" file="cros/snapshot_wide.png" /> <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_RECYCLE" file="cros/discard_wide.png" /> </if> - <structure type="chrome_scaled_image" name="IDR_WARNING" file="common/alert_small.png" /> <if expr="not _google_chrome"> <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON" file="chromium/webstore_icon.png" /> <structure type="chrome_scaled_image" name="IDR_WEBSTORE_ICON_16" file="chromium/webstore_icon_16.png" />
diff --git a/chrome/browser/accessibility/accessibility_extension_api.cc b/chrome/browser/accessibility/accessibility_extension_api.cc index 33760181..617c0a40 100644 --- a/chrome/browser/accessibility/accessibility_extension_api.cc +++ b/chrome/browser/accessibility/accessibility_extension_api.cc
@@ -408,4 +408,18 @@ return RespondNow(NoArguments()); } +ExtensionFunction::ResponseAction +AccessibilityPrivateForwardKeyEventsToSwitchAccessFunction::Run() { + std::unique_ptr<accessibility_private::ForwardKeyEventsToSwitchAccess::Params> + params = + accessibility_private::ForwardKeyEventsToSwitchAccess::Params::Create( + *args_); + EXTENSION_FUNCTION_VALIDATE(params); + + GetAccessibilityController()->ForwardKeyEventsToSwitchAccess( + params->should_forward); + + return RespondNow(NoArguments()); +} + #endif // defined (OS_CHROMEOS)
diff --git a/chrome/browser/accessibility/accessibility_extension_api.h b/chrome/browser/accessibility/accessibility_extension_api.h index 6489a7d..8f94901 100644 --- a/chrome/browser/accessibility/accessibility_extension_api.h +++ b/chrome/browser/accessibility/accessibility_extension_api.h
@@ -135,6 +135,17 @@ ACCESSIBILITY_PRIVATE_SETSWITCHACCESSMENUSTATE) }; +// API function that requests that key events be forwarded to the Switch +// Access extension. +class AccessibilityPrivateForwardKeyEventsToSwitchAccessFunction + : public UIThreadExtensionFunction { + ~AccessibilityPrivateForwardKeyEventsToSwitchAccessFunction() override {} + ResponseAction Run() override; + DECLARE_EXTENSION_FUNCTION( + "accessibilityPrivate.forwardKeyEventsToSwitchAccess", + ACCESSIBILITY_PRIVATE_FORWARDKEYEVENTSTOSWITCHACCESS) +}; + #endif // defined (OS_CHROMEOS) #endif // CHROME_BROWSER_ACCESSIBILITY_ACCESSIBILITY_EXTENSION_API_H_
diff --git a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc index 09681cea..eb59385 100644 --- a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc +++ b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.cc
@@ -19,6 +19,12 @@ } void EphemeralTabLayer::SetProperties( + int title_view_resource_id, + int caption_view_resource_id, + jfloat caption_animation_percentage, + jfloat text_layer_min_height, + jfloat title_caption_spacing, + jboolean caption_visible, int progress_bar_background_resource_id, int progress_bar_resource_id, float dp_to_px, @@ -29,7 +35,6 @@ float panel_height, float bar_margin_side, float bar_height, - float text_opacity, bool bar_border_visible, float bar_border_height, bool bar_shadow_visible, @@ -45,11 +50,19 @@ bool should_render_progress_bar = progress_bar_visible && progress_bar_opacity > 0.f; + // Title needs no rendering in the base layer as it can be rendered + // together with caption below. Make it invisible. + float title_opacity = 0.f; OverlayPanelLayer::SetProperties( dp_to_px, content_layer, bar_height, panel_x, panel_y, panel_width, - panel_height, bar_margin_side, bar_height, 0.0f, text_opacity, + panel_height, bar_margin_side, bar_height, 0.0f, title_opacity, bar_border_visible, bar_border_height, bar_shadow_visible, - bar_shadow_opacity, 1.0f); + bar_shadow_opacity, 1.0f /* icon opacity */); + + SetupTextLayer(bar_top, bar_height, text_layer_min_height, + caption_view_resource_id, caption_animation_percentage, + caption_visible, title_view_resource_id, + title_caption_spacing); // --------------------------------------------------------------------------- // Progress Bar @@ -107,14 +120,137 @@ } } +void EphemeralTabLayer::SetupTextLayer(float bar_top, + float bar_height, + float text_layer_min_height, + int caption_resource_id, + float animation_percentage, + bool caption_visible, + int title_resource_id, + float title_caption_spacing) { + // --------------------------------------------------------------------------- + // Setup the Drawing Hierarchy + // --------------------------------------------------------------------------- + + DCHECK(text_layer_.get()); + DCHECK(caption_.get()); + DCHECK(title_.get()); + + // Title + ui::Resource* title_resource = resource_manager_->GetResource( + ui::ANDROID_RESOURCE_TYPE_DYNAMIC, title_resource_id); + if (title_resource) { + title_->SetUIResourceId(title_resource->ui_resource()->id()); + title_->SetBounds(title_resource->size()); + } + + // Caption + ui::Resource* caption_resource = nullptr; + if (caption_visible) { + // Grabs the dynamic Search Caption resource so we can get a snapshot. + caption_resource = resource_manager_->GetResource( + ui::ANDROID_RESOURCE_TYPE_DYNAMIC, caption_resource_id); + } + + if (animation_percentage != 0.f) { + if (caption_->parent() != text_layer_) { + text_layer_->AddChild(caption_); + } + if (caption_resource) { + caption_->SetUIResourceId(caption_resource->ui_resource()->id()); + caption_->SetBounds(caption_resource->size()); + } + } else if (caption_->parent()) { + caption_->RemoveFromParent(); + } + + // --------------------------------------------------------------------------- + // Calculate Text Layer Size + // --------------------------------------------------------------------------- + // The caption_ may not have had its resource set by this point, if so + // the bounds will be zero and everything will still work. + float title_height = title_->bounds().height(); + float caption_height = caption_->bounds().height(); + + float layer_height = + std::max(text_layer_min_height, + title_height + caption_height + title_caption_spacing); + float layer_width = + std::max(title_->bounds().width(), caption_->bounds().width()); + + float layer_top = bar_top + (bar_height - layer_height) / 2; + text_layer_->SetBounds(gfx::Size(layer_width, layer_height)); + text_layer_->SetPosition(gfx::PointF(0.f, layer_top)); + text_layer_->SetMasksToBounds(true); + + // --------------------------------------------------------------------------- + // Layout Text Layer + // --------------------------------------------------------------------------- + // ---Top of Panel Bar--- <- bar_top + // + // ---Top of Text Layer--- <- layer_top + // } remaining_height / 2 + // Title } title_height + // } title_caption_spacing + // Caption } caption_height + // } remaining_height / 2 + // --Bottom of Text Layer- + // + // --Bottom of Panel Bar- + // If the Caption is not visible the Title is centered in this space, when + // the Caption becomes visible it is animated sliding up into it's position + // with the spacings determined by UI. + + // If there is no caption, just vertically center the title. + float title_top = (layer_height - title_height) / 2; + + // If we aren't displaying the caption we're done. + if (animation_percentage == 0.f || !caption_resource) { + title_->SetPosition(gfx::PointF(0.f, title_top)); + return; + } + + // Calculate the positions for the Title and Caption when the Caption + // animation is complete. + float remaining_height = + layer_height - title_height - title_caption_spacing - caption_height; + + float title_top_end = remaining_height / 2; + float caption_top_end = title_top_end + title_height + title_caption_spacing; + + // Interpolate between the animation start and end positions (short cut + // if the animation is at the end or start). + title_top = title_top * (1.f - animation_percentage) + + title_top_end * animation_percentage; + + // The Caption starts off the bottom of the Text Layer. + float caption_top = layer_height * (1.f - animation_percentage) + + caption_top_end * animation_percentage; + + title_->SetPosition(gfx::PointF(0.f, title_top)); + caption_->SetPosition(gfx::PointF(0.f, caption_top)); +} + EphemeralTabLayer::EphemeralTabLayer(ui::ResourceManager* resource_manager) : OverlayPanelLayer(resource_manager), + title_(cc::UIResourceLayer::Create()), + caption_(cc::UIResourceLayer::Create()), + text_layer_(cc::UIResourceLayer::Create()), progress_bar_(cc::NinePatchLayer::Create()), progress_bar_background_(cc::NinePatchLayer::Create()) { progress_bar_background_->SetIsDrawable(true); progress_bar_background_->SetFillCenter(true); progress_bar_->SetIsDrawable(true); progress_bar_->SetFillCenter(true); + + // Content layer + text_layer_->SetIsDrawable(true); + + title_->SetIsDrawable(true); + caption_->SetIsDrawable(true); + + AddBarTextLayer(text_layer_); + text_layer_->AddChild(title_); } EphemeralTabLayer::~EphemeralTabLayer() {}
diff --git a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h index f70c9fd..aa68719 100644 --- a/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h +++ b/chrome/browser/android/compositor/layer/ephemeral_tab_layer.h
@@ -23,7 +23,13 @@ public: static scoped_refptr<EphemeralTabLayer> Create( ui::ResourceManager* resource_manager); - void SetProperties(int progress_bar_background_resource_id, + void SetProperties(int title_view_resource_id, + int caption_view_resource_id, + jfloat caption_animation_percentage, + jfloat text_layer_min_height, + jfloat title_caption_spacing, + jboolean caption_visible, + int progress_bar_background_resource_id, int progress_bar_resource_id, float dp_to_px, const scoped_refptr<cc::Layer>& content_layer, @@ -33,7 +39,6 @@ float panel_height, float bar_margin_side, float bar_height, - float text_opacity, bool bar_border_visible, float bar_border_height, bool bar_shadow_visible, @@ -42,12 +47,23 @@ float progress_bar_height, float progress_bar_opacity, int progress_bar_completion); + void SetupTextLayer(float bar_top, + float bar_height, + float text_layer_min_height, + int caption_resource_id, + float animation_percentage, + bool caption_visible, + int context_resource_id, + float title_caption_spacing); protected: explicit EphemeralTabLayer(ui::ResourceManager* resource_manager); ~EphemeralTabLayer() override; private: + scoped_refptr<cc::UIResourceLayer> title_; + scoped_refptr<cc::UIResourceLayer> caption_; + scoped_refptr<cc::UIResourceLayer> text_layer_; scoped_refptr<cc::NinePatchLayer> progress_bar_; scoped_refptr<cc::NinePatchLayer> progress_bar_background_; };
diff --git a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc index 67571aa..a6429f91 100644 --- a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc +++ b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.cc
@@ -59,19 +59,24 @@ void EphemeralTabSceneLayer::Update(JNIEnv* env, const JavaParamRef<jobject>& object, + jint title_view_resource_id, + jint caption_view_resource_id, + jfloat caption_animation_percentage, + jfloat text_layer_min_height, + jfloat title_caption_spacing, + jboolean caption_visible, jint progress_bar_background_resource_id, jint progress_bar_resource_id, jfloat dp_to_px, jfloat base_page_brightness, jfloat base_page_offset, const JavaParamRef<jobject>& jweb_contents, - jfloat panel_X, + jfloat panel_x, jfloat panel_y, jfloat panel_width, jfloat panel_height, jfloat bar_margin_side, jfloat bar_height, - jfloat text_opacity, jboolean bar_border_visible, jfloat bar_border_height, jboolean bar_shadow_visible, @@ -100,12 +105,14 @@ // Move the base page contents up. content_container_->SetPosition(gfx::PointF(0.0f, base_page_offset)); ephemeral_tab_layer_->SetProperties( + title_view_resource_id, caption_view_resource_id, + caption_animation_percentage, text_layer_min_height, + title_caption_spacing, caption_visible, progress_bar_background_resource_id, progress_bar_resource_id, dp_to_px, - content_layer, panel_X, panel_y, panel_width, panel_height, - bar_margin_side, bar_height, text_opacity, bar_border_visible, - bar_border_height, bar_shadow_visible, bar_shadow_opacity, - progress_bar_visible, progress_bar_height, progress_bar_opacity, - progress_bar_completion); + content_layer, panel_x, panel_y, panel_width, panel_height, + bar_margin_side, bar_height, bar_border_visible, bar_border_height, + bar_shadow_visible, bar_shadow_opacity, progress_bar_visible, + progress_bar_height, progress_bar_opacity, progress_bar_completion); // Make the layer visible if it is not already. ephemeral_tab_layer_->layer()->SetHideLayerAndSubtree(false); }
diff --git a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h index 4931df1b..661d59b7 100644 --- a/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h +++ b/chrome/browser/android/compositor/scene_layer/ephemeral_tab_scene_layer.h
@@ -45,6 +45,12 @@ void Update(JNIEnv* env, const base::android::JavaParamRef<jobject>& object, + jint title_view_resource_id, + jint caption_view_resource_id, + jfloat caption_animation_percentage, + jfloat text_layer_min_height, + jfloat term_caption_spacing, + jboolean caption_visible, jint progress_bar_background_resource_id, jint progress_bar_resource_id, jfloat dp_to_px, @@ -57,7 +63,6 @@ jfloat panel_height, jfloat bar_margin_side, jfloat bar_height, - jfloat text_opacity, jboolean bar_border_visible, jfloat bar_border_height, jboolean bar_shadow_visible,
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc index 166981e1..f569dcd 100644 --- a/chrome/browser/android/download/download_controller.cc +++ b/chrome/browser/android/download/download_controller.cc
@@ -20,6 +20,7 @@ #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/android/download/dangerous_download_infobar_delegate.h" #include "chrome/browser/android/download/download_manager_service.h" +#include "chrome/browser/android/download/download_utils.h" #include "chrome/browser/android/tab_android.h" #include "chrome/browser/download/download_stats.h" #include "chrome/browser/infobars/infobar_service.h" @@ -28,6 +29,7 @@ #include "chrome/browser/ui/android/view_android_helper.h" #include "chrome/browser/vr/vr_tab_helper.h" #include "chrome/grit/chromium_strings.h" +#include "components/download/public/common/auto_resumption_handler.h" #include "components/download/public/common/download_url_parameters.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_task_traits.h" @@ -59,11 +61,6 @@ // Guards download_controller_ base::LazyInstance<base::Lock>::DestructorAtExit g_download_controller_lock_; -// If received bytes is more than the size limit and resumption will restart -// from the beginning, throttle it. -int kDefaultAutoResumptionSizeLimit = 10 * 1024 * 1024; // 10 MB -const char kAutoResumptionSizeLimitParamName[] = "AutoResumptionSizeLimit"; - void CreateContextMenuDownload( const content::ResourceRequestInfo::WebContentsGetter& wc_getter, const content::ContextMenuParams& params, @@ -116,16 +113,6 @@ dlm->DownloadUrl(std::move(dl_params)); } -int GetAutoResumptionSizeLimit() { - std::string value = base::GetFieldTrialParamValueByFeature( - chrome::android::kDownloadAutoResumptionThrottling, - kAutoResumptionSizeLimitParamName); - int size_limit; - return base::StringToInt(value, &size_limit) - ? size_limit - : kDefaultAutoResumptionSizeLimit; -} - // Helper class for retrieving a DownloadManager. class DownloadManagerGetter : public DownloadManager::Observer { public: @@ -395,6 +382,8 @@ download_item->RemoveObserver(this); download_item->AddObserver(this); + download::AutoResumptionHandler::Get()->OnDownloadStarted(download_item); + OnDownloadUpdated(download_item); } @@ -480,7 +469,7 @@ if (!download_item->GetURL().SchemeIsHTTPOrHTTPS()) return false; - static int size_limit = GetAutoResumptionSizeLimit(); + static int size_limit = DownloadUtils::GetAutoResumptionSizeLimit(); bool exceeds_size_limit = download_item->GetReceivedBytes() > size_limit; std::string etag = download_item->GetETag(); std::string last_modified = download_item->GetLastModifiedTime();
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc index aadb99c..7cab0040 100644 --- a/chrome/browser/android/download/download_manager_service.cc +++ b/chrome/browser/android/download/download_manager_service.cc
@@ -16,6 +16,8 @@ #include "base/time/time.h" #include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/android/download/download_controller.h" +#include "chrome/browser/android/download/download_utils.h" +#include "chrome/browser/android/download/service/download_task_scheduler.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/download/download_core_service.h" #include "chrome/browser/download/download_core_service_factory.h" @@ -23,6 +25,8 @@ #include "chrome/browser/net/system_network_context_manager.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/chrome_constants.h" +#include "components/download/network/android/network_status_listener_android.h" +#include "components/download/public/common/auto_resumption_handler.h" #include "components/download/public/common/download_item.h" #include "components/download/public/common/download_item_impl.h" #include "components/download/public/common/download_url_loader_factory_getter_impl.h" @@ -68,6 +72,21 @@ } // namespace // static +void DownloadManagerService::CreateAutoResumptionHandler() { + auto network_listener = + std::make_unique<download::NetworkStatusListenerAndroid>(); + auto task_scheduler = + std::make_unique<download::android::DownloadTaskScheduler>(); + auto task_manager = + std::make_unique<download::TaskManager>(std::move(task_scheduler)); + auto config = std::make_unique<download::AutoResumptionHandler::Config>(); + config->auto_resumption_size_limit = + DownloadUtils::GetAutoResumptionSizeLimit(); + download::AutoResumptionHandler::Create( + std::move(network_listener), std::move(task_manager), std::move(config)); +} + +// static void DownloadManagerService::OnDownloadCanceled( download::DownloadItem* download, DownloadController::DownloadCancelReason reason) { @@ -649,6 +668,22 @@ if (!in_progress_manager_ && !is_history_query_complete_) return; is_pending_downloads_loaded_ = true; + + // Kick-off the auto-resumption handler. + content::DownloadManager::DownloadVector all_items; + if (in_progress_manager_) { + in_progress_manager_->GetAllDownloads(&all_items); + } else { + content::DownloadManager* manager = GetDownloadManager(false); + if (manager) + manager->GetAllDownloads(&all_items); + } + + if (!download::AutoResumptionHandler::Get()) + CreateAutoResumptionHandler(); + + download::AutoResumptionHandler::Get()->SetResumableDownloads(all_items); + for (auto iter = pending_actions_.begin(); iter != pending_actions_.end(); ++iter) { DownloadActionParams params = iter->second;
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h index 61f69d7..d522e7ba 100644 --- a/chrome/browser/android/download/download_manager_service.h +++ b/chrome/browser/android/download/download_manager_service.h
@@ -38,6 +38,8 @@ public content::NotificationObserver, public service_manager::Service { public: + static void CreateAutoResumptionHandler(); + static void OnDownloadCanceled( download::DownloadItem* download, DownloadController::DownloadCancelReason reason);
diff --git a/chrome/browser/android/download/download_utils.cc b/chrome/browser/android/download/download_utils.cc index c413f75..27670e0 100644 --- a/chrome/browser/android/download/download_utils.cc +++ b/chrome/browser/android/download/download_utils.cc
@@ -5,6 +5,9 @@ #include "chrome/browser/android/download/download_utils.h" #include "base/android/jni_string.h" +#include "base/metrics/field_trial_params.h" +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/android/chrome_feature_list.h" #include "chrome/browser/download/offline_item_utils.h" #include "chrome/grit/generated_resources.h" #include "components/download/public/common/download_utils.h" @@ -15,6 +18,14 @@ using base::android::JavaParamRef; using base::android::ScopedJavaLocalRef; +namespace { +// If received bytes is more than the size limit and resumption will restart +// from the beginning, throttle it. +int kDefaultAutoResumptionSizeLimit = 10 * 1024 * 1024; // 10 MB +const char kAutoResumptionSizeLimitParamName[] = "AutoResumptionSizeLimit"; + +} // namespace + static ScopedJavaLocalRef<jstring> JNI_DownloadUtils_GetFailStateMessage( JNIEnv* env, jint fail_state) { @@ -46,3 +57,14 @@ return base::FilePath( base::android::ConvertJavaStringToUTF8(env, uri_jstring)); } + +// static +int DownloadUtils::GetAutoResumptionSizeLimit() { + std::string value = base::GetFieldTrialParamValueByFeature( + chrome::android::kDownloadAutoResumptionThrottling, + kAutoResumptionSizeLimitParamName); + int size_limit; + return base::StringToInt(value, &size_limit) + ? size_limit + : kDefaultAutoResumptionSizeLimit; +}
diff --git a/chrome/browser/android/download/download_utils.h b/chrome/browser/android/download/download_utils.h index b507ffa..73c0b27a 100644 --- a/chrome/browser/android/download/download_utils.h +++ b/chrome/browser/android/download/download_utils.h
@@ -11,6 +11,7 @@ class DownloadUtils { public: static base::FilePath GetUriStringForPath(const base::FilePath& file_path); + static int GetAutoResumptionSizeLimit(); }; #endif // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_UTILS_H_
diff --git a/chrome/browser/android/download/service/download_background_task.cc b/chrome/browser/android/download/service/download_background_task.cc index 86c394a..e418d089 100644 --- a/chrome/browser/android/download/service/download_background_task.cc +++ b/chrome/browser/android/download/service/download_background_task.cc
@@ -4,10 +4,12 @@ #include "base/android/callback_android.h" #include "base/callback_forward.h" +#include "chrome/browser/android/download/download_manager_service.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_android.h" #include "components/download/public/background_service/download_service.h" +#include "components/download/public/common/auto_resumption_handler.h" #include "content/public/browser/browser_context.h" #include "jni/DownloadBackgroundTask_jni.h" @@ -16,6 +18,19 @@ namespace download { namespace android { +DownloadService* GetDownloadService( + const base::android::JavaParamRef<jobject>& jprofile) { + Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); + DCHECK(profile); + return DownloadServiceFactory::GetForBrowserContext(profile); +} + +AutoResumptionHandler* GetAutoResumptionHandler() { + if (!AutoResumptionHandler::Get()) + DownloadManagerService::CreateAutoResumptionHandler(); + return AutoResumptionHandler::Get(); +} + // static void JNI_DownloadBackgroundTask_StartBackgroundTask( JNIEnv* env, @@ -23,17 +38,23 @@ const base::android::JavaParamRef<jobject>& jprofile, jint task_type, const base::android::JavaParamRef<jobject>& jcallback) { - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); - DCHECK(profile); - TaskFinishedCallback finish_callback = base::BindOnce(&base::android::RunBooleanCallbackAndroid, base::android::ScopedJavaGlobalRef<jobject>(jcallback)); - DownloadService* download_service = - DownloadServiceFactory::GetForBrowserContext(profile); - download_service->OnStartScheduledTask( - static_cast<DownloadTaskType>(task_type), std::move(finish_callback)); + switch (static_cast<DownloadTaskType>(task_type)) { + case download::DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK: { + GetAutoResumptionHandler()->OnStartScheduledTask( + std::move(finish_callback)); + break; + } + case download::DownloadTaskType::DOWNLOAD_TASK: + FALLTHROUGH; + case download::DownloadTaskType::CLEANUP_TASK: + GetDownloadService(jprofile)->OnStartScheduledTask( + static_cast<DownloadTaskType>(task_type), std::move(finish_callback)); + break; + } } // static @@ -42,13 +63,18 @@ const base::android::JavaParamRef<jobject>& jcaller, const base::android::JavaParamRef<jobject>& jprofile, jint task_type) { - Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile); - DCHECK(profile); - - DownloadService* download_service = - DownloadServiceFactory::GetForBrowserContext(profile); - return download_service->OnStopScheduledTask( - static_cast<DownloadTaskType>(task_type)); + switch (static_cast<DownloadTaskType>(task_type)) { + case download::DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK: { + GetAutoResumptionHandler()->OnStopScheduledTask(); + break; + } + case download::DownloadTaskType::DOWNLOAD_TASK: + FALLTHROUGH; + case download::DownloadTaskType::CLEANUP_TASK: + return GetDownloadService(jprofile)->OnStopScheduledTask( + static_cast<DownloadTaskType>(task_type)); + } + return false; } } // namespace android
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc index 1a6905df..e26e149 100644 --- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc +++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -268,6 +268,8 @@ input_.from_omnibox_focus() ? base::string16() : input_.text(), false, /* don't know */ input_.type(), + false, /* not keyword mode */ + OmniboxEventProto::INVALID, true, selected_index, WindowOpenDisposition::CURRENT_TAB,
diff --git a/chrome/browser/android/vr/arcore_device/arcore.h b/chrome/browser/android/vr/arcore_device/arcore.h index 9b0b0cf..cd57addb 100644 --- a/chrome/browser/android/vr/arcore_device/arcore.h +++ b/chrome/browser/android/vr/arcore_device/arcore.h
@@ -45,7 +45,6 @@ virtual bool RequestHitTest( const mojom::XRRayPtr& ray, - const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) = 0; virtual void Pause() = 0;
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.cc b/chrome/browser/android/vr/arcore_device/arcore_gl.cc index 370b03a..1f6a024 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.cc
@@ -265,8 +265,7 @@ gl_thread_task_runner_->PostTask( FROM_HERE, base::BindOnce(&ArCoreGl::ProcessFrame, weak_ptr_factory_.GetWeakPtr(), - base::Passed(&frame_data), frame_size, - base::Passed(&callback))); + base::Passed(&frame_data), base::Passed(&callback))); } void ArCoreGl::RequestHitTest( @@ -284,7 +283,6 @@ void ArCoreGl::ProcessFrame( mojom::XRFrameDataPtr frame_data, - const gfx::Size& frame_size, mojom::XRFrameDataProvider::GetFrameDataCallback callback) { DCHECK(IsOnGlThread()); DCHECK(is_initialized_); @@ -304,7 +302,7 @@ // obvious how the timing between the results and the frame should go. for (auto& request : hit_test_requests_) { std::vector<mojom::XRHitResultPtr> results; - if (arcore_->RequestHitTest(request->ray, frame_size, &results)) { + if (arcore_->RequestHitTest(request->ray, &results)) { std::move(request->callback).Run(std::move(results)); } else { // Hit test failed, i.e. unprojected location was offscreen.
diff --git a/chrome/browser/android/vr/arcore_device/arcore_gl.h b/chrome/browser/android/vr/arcore_device/arcore_gl.h index 1dd2d82..e12f33a 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_gl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_gl.h
@@ -67,9 +67,7 @@ base::WeakPtr<ArCoreGl> GetWeakPtr(); private: - // TODO(https://crbug/835948): remove frame_size. void ProcessFrame(mojom::XRFrameDataPtr frame_data, - const gfx::Size& frame_size, mojom::XRFrameDataProvider::GetFrameDataCallback callback); bool InitializeGl();
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.cc b/chrome/browser/android/vr/arcore_device/arcore_impl.cc index 5ddb02e9..3fd89bd 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.cc
@@ -207,10 +207,8 @@ return result; } -// TODO(835948): remove image-size bool ArCoreImpl::RequestHitTest( const mojom::XRRayPtr& ray, - const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) { DCHECK(IsOnGlThread()); DCHECK(arcore_session_.is_valid()); @@ -227,17 +225,14 @@ return false; } - gfx::PointF screen_point; - if (!TransformRayToScreenSpace(ray, image_size, &screen_point)) { - return false; - } - // ArCore returns hit-results in sorted order, thus providing the guarantee // of sorted results promised by the WebXR spec for requestHitTest(). - ArFrame_hitTest(arcore_session_.get(), arcore_frame_.get(), - screen_point.x() * image_size.width(), - screen_point.y() * image_size.height(), - arcore_hit_result_list.get()); + float origin[3] = {ray->origin.x(), ray->origin.y(), ray->origin.z()}; + float direction[3] = {ray->direction.x(), ray->direction.y(), + ray->direction.z()}; + + ArFrame_hitTestRay(arcore_session_.get(), arcore_frame_.get(), origin, + direction, arcore_hit_result_list.get()); int arcore_hit_result_list_size = 0; ArHitResultList_getSize(arcore_session_.get(), arcore_hit_result_list.get(), @@ -315,61 +310,6 @@ return true; } -// TODO(835948): remove this method. -bool ArCoreImpl::TransformRayToScreenSpace(const mojom::XRRayPtr& ray, - const gfx::Size& image_size, - gfx::PointF* screen_point) { - DCHECK(IsOnGlThread()); - DCHECK(arcore_session_.is_valid()); - DCHECK(arcore_frame_.is_valid()); - - internal::ScopedArCoreObject<ArCamera*> arcore_camera; - ArFrame_acquireCamera( - arcore_session_.get(), arcore_frame_.get(), - internal::ScopedArCoreObject<ArCamera*>::Receiver(arcore_camera).get()); - DCHECK(arcore_camera.is_valid()) - << "ArFrame_acquireCamera failed despite documentation saying it cannot"; - - // Get the projection matrix. - float projection_matrix[16]; - ArCamera_getProjectionMatrix(arcore_session_.get(), arcore_camera.get(), 0.1, - 1000, projection_matrix); - SkMatrix44 projection44; - projection44.setColMajorf(projection_matrix); - gfx::Transform projection_transform(projection44); - - // Get the view matrix. - float view_matrix[16]; - ArCamera_getViewMatrix(arcore_session_.get(), arcore_camera.get(), - view_matrix); - SkMatrix44 view44; - view44.setColMajorf(view_matrix); - gfx::Transform view_transform(view44); - - // Create the combined matrix. - gfx::Transform proj_view_transform = projection_transform * view_transform; - - // Transform the ray into screen space. - gfx::Point3F screen_point_3d = ray->origin + ray->direction; - - proj_view_transform.TransformPoint(&screen_point_3d); - if (screen_point_3d.x() < -1 || screen_point_3d.x() > 1 || - screen_point_3d.y() < -1 || screen_point_3d.y() > 1) { - // The point does not project back into screen space, so this won't - // work with the screen-space-based hit-test API. - DLOG(ERROR) << "Invalid ray - does not originate from device screen."; - return false; - } - - screen_point->set_x((screen_point_3d.x() + 1) / 2); - // The calculated point in GL's normalized device coordinates (NDC) ranges - // from -1..1, with -1, -1 at the bottom left of the screen, +1 at the top. - // The output screen space coordinates range from 0..1, with 0, 0 at the - // top left. - screen_point->set_y((-screen_point_3d.y() + 1) / 2); - return true; -} - bool ArCoreImpl::IsOnGlThread() { return gl_thread_task_runner_->BelongsToCurrentThread(); }
diff --git a/chrome/browser/android/vr/arcore_device/arcore_impl.h b/chrome/browser/android/vr/arcore_device/arcore_impl.h index 2561e08..344d7fa 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_impl.h +++ b/chrome/browser/android/vr/arcore_device/arcore_impl.h
@@ -82,14 +82,9 @@ void Pause() override; void Resume() override; bool RequestHitTest(const mojom::XRRayPtr& ray, - const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) override; private: - bool TransformRayToScreenSpace(const mojom::XRRayPtr& ray, - const gfx::Size& image_size, - gfx::PointF* screen_point); - bool IsOnGlThread(); base::WeakPtr<ArCoreImpl> GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr();
diff --git a/chrome/browser/android/vr/arcore_device/arcore_shim.cc b/chrome/browser/android/vr/arcore_device/arcore_shim.cc index 98a009875..9b9fabff 100644 --- a/chrome/browser/android/vr/arcore_device/arcore_shim.cc +++ b/chrome/browser/android/vr/arcore_device/arcore_shim.cc
@@ -22,7 +22,7 @@ CALL(ArFrame_acquireCamera) \ CALL(ArFrame_create) \ CALL(ArFrame_destroy) \ - CALL(ArFrame_hitTest) \ + CALL(ArFrame_hitTestRay) \ CALL(ArFrame_transformDisplayUvCoords) \ CALL(ArHitResult_create) \ CALL(ArHitResult_destroy) \ @@ -152,13 +152,13 @@ arcore_api->impl_ArFrame_destroy(frame); } -void ArFrame_hitTest(const ArSession* session, - const ArFrame* frame, - float pixel_x, - float pixel_y, - ArHitResultList* out_hit_results) { - arcore_api->impl_ArFrame_hitTest(session, frame, pixel_x, pixel_y, - out_hit_results); +void ArFrame_hitTestRay(const ArSession* session, + const ArFrame* frame, + const float* ray_origin_3, + const float* ray_direction_3, + ArHitResultList* out_hit_results) { + arcore_api->impl_ArFrame_hitTestRay(session, frame, ray_origin_3, + ray_direction_3, out_hit_results); } void ArFrame_transformDisplayUvCoords(const ArSession* session,
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.cc b/chrome/browser/android/vr/arcore_device/fake_arcore.cc index b4bdfc19..1205748 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.cc +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.cc
@@ -203,7 +203,6 @@ bool FakeArCore::RequestHitTest( const mojom::XRRayPtr& ray, - const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) { mojom::XRHitResultPtr hit = mojom::XRHitResult::New(); hit->hit_matrix.resize(16);
diff --git a/chrome/browser/android/vr/arcore_device/fake_arcore.h b/chrome/browser/android/vr/arcore_device/fake_arcore.h index d78672a..12b560d8 100644 --- a/chrome/browser/android/vr/arcore_device/fake_arcore.h +++ b/chrome/browser/android/vr/arcore_device/fake_arcore.h
@@ -35,7 +35,6 @@ void Resume() override; bool RequestHitTest(const mojom::XRRayPtr& ray, - const gfx::Size& image_size, std::vector<mojom::XRHitResultPtr>* hit_results) override; void SetCameraAspect(float aspect) { camera_aspect_ = aspect; }
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc index e2e4e921..6b5b551a 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.cc +++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "build/build_config.h" +#include "chrome/app/vector_icons/vector_icons.h" #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h" #include "chrome/browser/browsing_data/browsing_data_flash_lso_helper.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" @@ -32,7 +33,9 @@ #include "net/url_request/url_request_context.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/color_palette.h" #include "ui/gfx/image/image_skia.h" +#include "ui/gfx/paint_vector_icon.h" #include "ui/resources/grit/ui_resources.h" #include "url/gurl.h" #include "url/origin.h" @@ -1175,12 +1178,8 @@ // Returns the set of icons for the nodes in the tree. You only need override // this if you don't want to use the default folder icons. void CookiesTreeModel::GetIcons(std::vector<gfx::ImageSkia>* icons) { - icons->push_back(*ui::ResourceBundle::GetSharedInstance() - .GetNativeImageNamed(IDR_DEFAULT_FAVICON) - .ToImageSkia()); - icons->push_back(*ui::ResourceBundle::GetSharedInstance() - .GetNativeImageNamed(IDR_COOKIES) - .ToImageSkia()); + icons->push_back( + gfx::CreateVectorIcon(kCookieIcon, 18, gfx::kChromeIconGrey)); icons->push_back(*ui::ResourceBundle::GetSharedInstance() .GetNativeImageNamed(IDR_COOKIE_STORAGE_ICON) .ToImageSkia()); @@ -1192,8 +1191,6 @@ int CookiesTreeModel::GetIconIndex(ui::TreeModelNode* node) { CookieTreeNode* ct_node = static_cast<CookieTreeNode*>(node); switch (ct_node->GetDetailedInfo().node_type) { - case CookieTreeNode::DetailedInfo::TYPE_HOST: - return ORIGIN; case CookieTreeNode::DetailedInfo::TYPE_COOKIE: return COOKIE; @@ -1209,6 +1206,7 @@ case CookieTreeNode::DetailedInfo::TYPE_CACHE_STORAGE: case CookieTreeNode::DetailedInfo::TYPE_MEDIA_LICENSE: return DATABASE; + case CookieTreeNode::DetailedInfo::TYPE_HOST: case CookieTreeNode::DetailedInfo::TYPE_QUOTA: return -1; default:
diff --git a/chrome/browser/browsing_data/cookies_tree_model.h b/chrome/browser/browsing_data/cookies_tree_model.h index 56041697..2ecf397 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.h +++ b/chrome/browser/browsing_data/cookies_tree_model.h
@@ -865,11 +865,7 @@ static std::unique_ptr<CookiesTreeModel> CreateForProfile(Profile* profile); private: - enum CookieIconIndex { - ORIGIN = 0, - COOKIE = 1, - DATABASE = 2 - }; + enum CookieIconIndex { COOKIE = 0, DATABASE = 1 }; // Reset the counters for batches. void ResetBatches();
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 2182646..17539ab 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -111,6 +111,7 @@ "//chromeos/services/multidevice_setup/public/cpp:oobe_completion_tracker", "//chromeos/services/multidevice_setup/public/cpp:prefs", "//chromeos/services/secure_channel/public/cpp/client", + "//chromeos/tpm", "//components/arc", "//components/arc/common:struct_traits", "//components/arc/media_session",
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc index 8ec9dcd..738dbfb 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -84,6 +84,7 @@ #include "media/audio/sounds/sounds_manager.h" #include "mojo/public/cpp/bindings/binding.h" #include "services/media_session/public/cpp/switches.h" +#include "services/media_session/public/mojom/constants.mojom.h" #include "services/service_manager/public/cpp/connector.h" #include "ui/accessibility/accessibility_switches.h" #include "ui/accessibility/ax_enum_util.h" @@ -322,6 +323,12 @@ ->BindInterface(ash::mojom::kServiceName, &accessibility_focus_ring_controller_); + // Connect to the media session service. + content::ServiceManagerConnection::GetForProcess() + ->GetConnector() + ->BindInterface(media_session::mojom::kServiceName, + &audio_focus_manager_ptr_); + CrasAudioHandler::Get()->AddAudioObserver(this); } @@ -1325,11 +1332,15 @@ base::Unretained(this)))); } + // TODO(beccahughes): Remove once we have moved to a feature. if (!base::CommandLine::ForCurrentProcess()->HasSwitch( media_session::switches::kEnableAudioFocus)) { base::CommandLine::ForCurrentProcess()->AppendSwitch( media_session::switches::kEnableAudioFocus); } + + audio_focus_manager_ptr_->SetEnforcementMode( + media_session::mojom::EnforcementMode::kSingleSession); } void AccessibilityManager::PostUnloadChromeVox() { @@ -1355,6 +1366,9 @@ // Stop speech. content::TtsController::GetInstance()->Stop(); + + audio_focus_manager_ptr_->SetEnforcementMode( + media_session::mojom::EnforcementMode::kDefault); } void AccessibilityManager::PostSwitchChromeVoxProfile() {
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h index 0080332c..b6e11be 100644 --- a/chrome/browser/chromeos/accessibility/accessibility_manager.h +++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -28,6 +28,7 @@ #include "content/public/browser/notification_registrar.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_system.h" +#include "services/media_session/public/mojom/audio_focus.mojom.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/base/ime/chromeos/input_method_manager.h" @@ -468,6 +469,9 @@ base::RepeatingCallback<void(const gfx::Rect&)> caret_bounds_observer_for_test_; + // Used to set the audio focus enforcement type for ChromeVox. + media_session::mojom::AudioFocusManagerPtr audio_focus_manager_ptr_; + base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_; friend class DictationTest;
diff --git a/chrome/browser/chromeos/login/configuration_keys.cc b/chrome/browser/chromeos/login/configuration_keys.cc index d22894c..284cb46b 100644 --- a/chrome/browser/chromeos/login/configuration_keys.cc +++ b/chrome/browser/chromeos/login/configuration_keys.cc
@@ -12,6 +12,12 @@ // All keys should be listed here, even if they are used in JS code only. // These keys are used in chrome/browser/resources/chromeos/login/oobe_types.js +// == HID Detection screen: + +// Boolean value indicating if we should skip HID detection screen altogether. + +const char kSkipHIDDetection[] = "skipHIDDetection"; + // == Welcome screen: // Boolean value indicating if "Next" button on welcome screen is pressed @@ -109,6 +115,8 @@ ValueType type; ConfigurationHandlerSide side; } kAllConfigurationKeys[] = { + {kSkipHIDDetection, ValueType::BOOLEAN, + ConfigurationHandlerSide::HANDLER_CPP}, {kWelcomeNext, ValueType::BOOLEAN, ConfigurationHandlerSide::HANDLER_JS}, {kLanguage, ValueType::STRING, ConfigurationHandlerSide::HANDLER_JS}, {kInputMethod, ValueType::STRING, ConfigurationHandlerSide::HANDLER_JS},
diff --git a/chrome/browser/chromeos/login/configuration_keys.h b/chrome/browser/chromeos/login/configuration_keys.h index 8bc2ffc..3d4573d 100644 --- a/chrome/browser/chromeos/login/configuration_keys.h +++ b/chrome/browser/chromeos/login/configuration_keys.h
@@ -12,6 +12,8 @@ // Configuration keys that are used to automate OOBE screens go here. // Please keep keys grouped by screens and ordered according to OOBE flow. +extern const char kSkipHIDDetection[]; + extern const char kLanguage[]; extern const char kInputMethod[]; extern const char kWelcomeNext[];
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc index 03d8c86..876b207 100644 --- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc +++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -36,6 +36,12 @@ #include "components/prefs/pref_service.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_utils.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" +#include "device/bluetooth/test/mock_bluetooth_adapter.h" +#include "services/device/public/cpp/hid/fake_input_service_linux.h" +#include "services/device/public/mojom/constants.mojom.h" +#include "services/device/public/mojom/input_service.mojom.h" +#include "services/service_manager/public/cpp/service_binding.h" #include "ui/base/ime/chromeos/input_method_manager.h" #include "ui/base/ime/chromeos/input_method_util.h" @@ -560,6 +566,11 @@ DISALLOW_COPY_AND_ASSIGN(ActiveDirectoryJoinTest); }; +// This test case will use +// src/chromeos/test/data/oobe_configuration/<TestName>.json file as +// OOBE configuration for each of the tests and verify that relevant parts +// of OOBE automation took place. OOBE WebUI will not be started until +// LoadConfiguration() is called to allow configure relevant stubs. class EnterpriseEnrollmentConfigurationTest : public EnterpriseEnrollmentTestBase { public: @@ -696,6 +707,54 @@ DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentConfigurationTest); }; +// EnterpriseEnrollmentConfigurationTest with no input devices. +class EnterpriseEnrollmentConfigurationTestNoHID + : public EnterpriseEnrollmentConfigurationTest { + public: + using InputDeviceInfoPtr = device::mojom::InputDeviceInfoPtr; + + EnterpriseEnrollmentConfigurationTestNoHID() { + fake_input_service_manager_ = + std::make_unique<device::FakeInputServiceLinux>(); + + service_manager::ServiceBinding::OverrideInterfaceBinderForTesting( + device::mojom::kServiceName, + base::BindRepeating( + &device::FakeInputServiceLinux::Bind, + base::Unretained(fake_input_service_manager_.get()))); + } + + ~EnterpriseEnrollmentConfigurationTestNoHID() override { + service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting< + device::mojom::InputDeviceManager>(device::mojom::kServiceName); + } + + void SetUpInProcessBrowserTestFixture() override { + EnterpriseEnrollmentConfigurationTest::SetUpInProcessBrowserTestFixture(); + + mock_adapter_ = new testing::NiceMock<device::MockBluetoothAdapter>(); + + device::BluetoothAdapterFactory::SetAdapterForTesting(mock_adapter_); + EXPECT_CALL(*mock_adapter_, IsPresent()) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*mock_adapter_, IsPowered()) + .WillRepeatedly(testing::Return(true)); + EXPECT_CALL(*mock_adapter_, GetDevices()) + .WillRepeatedly( + testing::Return(device::BluetoothAdapter::ConstDeviceList())); + + // Note: The SecureChannel service, which is never destroyed until the + // browser process is killed, utilizes |mock_adapter_|. + testing::Mock::AllowLeak(mock_adapter_.get()); + } + + private: + std::unique_ptr<device::FakeInputServiceLinux> fake_input_service_manager_; + scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>> mock_adapter_; + + DISALLOW_COPY_AND_ASSIGN(EnterpriseEnrollmentConfigurationTestNoHID); +}; + #if defined(MEMORY_SANITIZER) #define TEST_DISABLED_ON_MSAN(test_fixture, test_name) \ IN_PROC_BROWSER_TEST_F(test_fixture, DISABLED_##test_name) @@ -1123,4 +1182,20 @@ EXPECT_TRUE(IsStepDisplayed("success")); } +// Check that HID detection screen is shown if it is not specified by +// configuration. +IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentConfigurationTestNoHID, + TestLeaveWelcomeScreen) { + LoadConfiguration(); + OobeScreenWaiter(OobeScreen::SCREEN_OOBE_HID_DETECTION).Wait(); +} + +// Check that HID detection screen is really skipped and rest of configuration +// is applied. +IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentConfigurationTestNoHID, + TestSkipHIDDetection) { + LoadConfiguration(); + OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait(); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 526537d6..ad900e5e 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -1301,11 +1301,14 @@ if (!GetOobeUI()) return; - if (screen_needed) { + const auto* skip_screen_key = oobe_configuration_.FindKeyOfType( + configuration::kSkipHIDDetection, base::Value::Type::BOOLEAN); + const bool skip_screen = skip_screen_key && skip_screen_key->GetBool(); + + if (screen_needed && !skip_screen) ShowHIDDetectionScreen(); - } else { + else ShowWelcomeScreen(); - } } void WizardController::UpdateOobeConfiguration() {
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc index 51f7253..490726c 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.cc +++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -150,6 +150,12 @@ std::move(shares_callback)); } +void SmbService::UpdateCredentials(int32_t mount_id, + const std::string& username, + const std::string& password) { + NOTREACHED(); +} + void SmbService::CallMount(const file_system_provider::MountOptions& options, const base::FilePath& share_path, const std::string& username_input, @@ -490,6 +496,12 @@ void SmbService::RequestCredentials(const std::string& share_path, int32_t mount_id, base::OnceClosure reply) { + update_credential_replies_[mount_id] = std::move(reply); + OpenRequestCredentialsDialog(share_path, mount_id); +} + +void SmbService::OpenRequestCredentialsDialog(const std::string& share_path, + int32_t mount_id) { NOTREACHED(); }
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h index 415bddcc..4391c43 100644 --- a/chrome/browser/chromeos/smb_client/smb_service.h +++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -5,6 +5,7 @@ #ifndef CHROME_BROWSER_CHROMEOS_SMB_CLIENT_SMB_SERVICE_H_ #define CHROME_BROWSER_CHROMEOS_SMB_CLIENT_SMB_SERVICE_H_ +#include <map> #include <memory> #include <string> @@ -84,6 +85,13 @@ void GatherSharesInNetwork(HostDiscoveryResponse discovery_callback, GatherSharesResponse shares_callback); + // Updates the credentials for |mount_id|. If there is a stored callback in + // |update_credentials_replies_| for |mount_id|, it will be run upon once the + // credentials are successfully updated. + void UpdateCredentials(int32_t mount_id, + const std::string& username, + const std::string& password); + private: // Calls SmbProviderClient::Mount(). |temp_file_manager_| must be initialized // before this is called. @@ -168,6 +176,11 @@ int32_t mount_id, base::OnceClosure reply); + // Opens a request credential dialog for the share path |share_path|. + // When a user clicks "Update" in the dialog, UpdateCredentials is run. + void OpenRequestCredentialsDialog(const std::string& share_path, + int32_t mount_id); + // Records metrics on the number of SMB mounts a user has. void RecordMountCount() const; @@ -176,6 +189,8 @@ Profile* profile_; std::unique_ptr<TempFileManager> temp_file_manager_; std::unique_ptr<SmbShareFinder> share_finder_; + // |mount_id| -> |reply|. Stored callbacks to run after updating credential. + std::map<int32_t, base::OnceClosure> update_credential_replies_; DISALLOW_COPY_AND_ASSIGN(SmbService); };
diff --git a/chrome/browser/download/download_task_scheduler_impl.cc b/chrome/browser/download/download_task_scheduler_impl.cc index 325ae9b..d12556d 100644 --- a/chrome/browser/download/download_task_scheduler_impl.cc +++ b/chrome/browser/download/download_task_scheduler_impl.cc
@@ -49,6 +49,11 @@ void DownloadTaskSchedulerImpl::RunScheduledTask( download::DownloadTaskType task_type) { + if (task_type == download::DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK) { + NOTREACHED(); + return; + } + download::DownloadService* download_service = DownloadServiceFactory::GetForBrowserContext(context_); download_service->OnStartScheduledTask(
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc index 6070e39..5f411dd 100644 --- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -920,7 +920,8 @@ .SetWithholdHostPermissions(true); EXPECT_TRUE(listener.WaitUntilSatisfied()); - // Navigate the browser to a page in a new tab. + // Navigate the browser to a page in a new tab. The page at "a.com" has two + // two cross-origin iframes to "b.com" and "c.com". const std::string kHost = "a.com"; GURL url = embedded_test_server()->GetURL(kHost, "/iframe_cross_site.html"); NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); @@ -934,17 +935,10 @@ ExtensionActionRunner::GetForWebContents(web_contents); ASSERT_TRUE(runner); - int port = embedded_test_server()->port(); - const std::string kXhrPath = "simple.html"; - // The extension shouldn't have currently received any webRequest events, - // since it doesn't have permission (and shouldn't receive any from an XHR). + // since it doesn't have any permissions. EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); - EXPECT_FALSE( - HasSeenWebRequestInBackgroundPage(extension, profile(), "b.com")); - content::RenderFrameHost* main_frame = nullptr; - content::RenderFrameHost* child_frame = nullptr; auto get_main_and_child_frame = [](content::WebContents* web_contents, content::RenderFrameHost** main_frame, content::RenderFrameHost** child_frame) { @@ -957,42 +951,53 @@ ASSERT_TRUE(*child_frame); }; + content::RenderFrameHost* main_frame = nullptr; + content::RenderFrameHost* child_frame = nullptr; get_main_and_child_frame(web_contents, &main_frame, &child_frame); const std::string kMainHost = main_frame->GetLastCommittedURL().host(); const std::string kChildHost = child_frame->GetLastCommittedURL().host(); + int port = embedded_test_server()->port(); + const std::string kXhrPath = "simple.html"; + + // The extension shouldn't be able to intercept the xhr requests since it + // doesn't have any permissions. PerformXhrInFrame(main_frame, kHost, port, kXhrPath); PerformXhrInFrame(child_frame, kChildHost, port, kXhrPath); EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); EXPECT_EQ(BLOCKED_ACTION_WEB_REQUEST, runner->GetBlockedActions(extension)); - // Grant activeTab permission, and perform another XHR. The extension should - // receive the event. + // Grant activeTab permission. runner->set_default_bubble_close_action_for_testing( base::WrapUnique(new ToolbarActionsBarBubbleDelegate::CloseAction( ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE))); runner->RunAction(extension, true); base::RunLoop().RunUntilIdle(); EXPECT_TRUE(content::WaitForLoadStop(web_contents)); - // The runner will have refreshed the page... + + // The runner will have refreshed the page, and the extension will have + // received access to the main-frame ("a.com") and requests initiated by it + // (cross-origin sub-frame navigations to "b.com" and "c.com"). get_main_and_child_frame(web_contents, &main_frame, &child_frame); + EXPECT_TRUE(HasSeenWebRequestInBackgroundPage(extension, profile(), "a.com")); + EXPECT_TRUE(HasSeenWebRequestInBackgroundPage(extension, profile(), "b.com")); + EXPECT_TRUE(HasSeenWebRequestInBackgroundPage(extension, profile(), "c.com")); + EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension)); - int xhr_count = GetWebRequestCountFromBackgroundPage(extension, profile()); - // ... which means that we should have a non-zero xhr count, and the extension - // should see the request for the cross-site subframe... - EXPECT_GT(xhr_count, 0); - EXPECT_TRUE(HasSeenWebRequestInBackgroundPage(extension, profile(), "b.com")); + int request_count = + GetWebRequestCountFromBackgroundPage(extension, profile()); + // ... and the extension should receive future events. PerformXhrInFrame(main_frame, kHost, port, kXhrPath); - ++xhr_count; - EXPECT_EQ(xhr_count, + ++request_count; + EXPECT_EQ(request_count, GetWebRequestCountFromBackgroundPage(extension, profile())); // However, activeTab only grants access to the main frame, not to child // frames. As such, trying to XHR in the child frame should still fail. PerformXhrInFrame(child_frame, kChildHost, port, kXhrPath); - EXPECT_EQ(xhr_count, + EXPECT_EQ(request_count, GetWebRequestCountFromBackgroundPage(extension, profile())); // But since there's no way for the user to currently grant access to child // frames, this shouldn't show up as a blocked action. @@ -1014,7 +1019,7 @@ action_updated_waiter.Wait(); EXPECT_EQ(web_contents, action_updated_waiter.last_web_contents()); - EXPECT_EQ(xhr_count, + EXPECT_EQ(request_count, GetWebRequestCountFromBackgroundPage(extension, profile())); EXPECT_EQ(BLOCKED_ACTION_WEB_REQUEST, runner->GetBlockedActions(extension)); }
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc index dbbecc9..b14136b 100644 --- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc +++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -593,6 +593,35 @@ "nosniff.xml - body\n"); } +// Tests that same-origin fetches (same-origin relative to the webpage the +// content script is injected into) are allowed. See also +// https://crbug.com/918660. +IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest, + FromProgrammaticContentScript_SameOrigin) { + // Load the test extension. + ASSERT_TRUE(InstallExtension()); + + // Navigate to a foo.com page. + GURL page_url = GetTestPageUrl("foo.com"); + ui_test_utils::NavigateToURL(browser(), page_url); + ASSERT_EQ(page_url, + active_web_contents()->GetMainFrame()->GetLastCommittedURL()); + ASSERT_EQ(url::Origin::Create(page_url), + active_web_contents()->GetMainFrame()->GetLastCommittedOrigin()); + + // Inject a content script that performs a same-origin XHR to foo.com. + base::HistogramTester histograms; + GURL same_origin_resource( + embedded_test_server()->GetURL("foo.com", "/nosniff.xml")); + std::string fetch_result = + FetchViaContentScript(same_origin_resource, active_web_contents()); + + // Verify that no blocking occurred. + EXPECT_THAT(fetch_result, ::testing::StartsWith("nosniff.xml - body")); + VerifyFetchFromContentScriptWasAllowed(histograms, + false /* expecting_sniffing */); +} + // Test that responses that would have been allowed by CORB anyway are not // reported to LogInitiatorSchemeBypassingDocumentBlocking. IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
diff --git a/chrome/browser/interstitials/enterprise_util.cc b/chrome/browser/interstitials/enterprise_util.cc index 6597a0a5..81ba4a6a 100644 --- a/chrome/browser/interstitials/enterprise_util.cc +++ b/chrome/browser/interstitials/enterprise_util.cc
@@ -97,6 +97,7 @@ case safe_browsing::SB_THREAT_TYPE_AD_SAMPLE: case safe_browsing::SB_THREAT_TYPE_SUSPICIOUS_SITE: case safe_browsing::SB_THREAT_TYPE_ENTERPRISE_PASSWORD_REUSE: + case safe_browsing::SB_THREAT_TYPE_APK_DOWNLOAD: NOTREACHED(); break; }
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc index 9d611db..3472068 100644 --- a/chrome/browser/offline_pages/android/offline_page_bridge.cc +++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -65,6 +65,25 @@ const char kOfflinePageBridgeKey[] = "offline-page-bridge"; +void JNI_SavePageRequest_ToJavaOfflinePageList( + JNIEnv* env, + const JavaRef<jobject>& j_result_obj, + const std::vector<OfflinePageItem>& offline_pages) { + for (const OfflinePageItem& offline_page : offline_pages) { + Java_OfflinePageBridge_createOfflinePageAndAddToList( + env, j_result_obj, + ConvertUTF8ToJavaString(env, offline_page.url.spec()), + offline_page.offline_id, + ConvertUTF8ToJavaString(env, offline_page.client_id.name_space), + ConvertUTF8ToJavaString(env, offline_page.client_id.id), + ConvertUTF16ToJavaString(env, offline_page.title), + ConvertUTF8ToJavaString(env, offline_page.file_path.value()), + offline_page.file_size, offline_page.creation_time.ToJavaTime(), + offline_page.access_count, offline_page.last_access_time.ToJavaTime(), + ConvertUTF8ToJavaString(env, offline_page.request_origin)); + } +} + ScopedJavaLocalRef<jobject> JNI_SavePageRequest_ToJavaOfflinePageItem( JNIEnv* env, const OfflinePageItem& offline_page) { @@ -95,7 +114,7 @@ const ScopedJavaGlobalRef<jobject>& j_callback_obj, const OfflinePageModel::MultipleOfflinePageItemResult& result) { JNIEnv* env = base::android::AttachCurrentThread(); - OfflinePageBridge::AddOfflinePageItemsToJavaList(env, j_result_obj, result); + JNI_SavePageRequest_ToJavaOfflinePageList(env, j_result_obj, result); base::android::RunObjectCallbackAndroid(j_callback_obj, j_result_obj); } @@ -215,8 +234,31 @@ ScopedJavaLocalRef<jobjectArray> JNI_SavePageRequest_CreateJavaSavePageRequests( JNIEnv* env, std::vector<std::unique_ptr<SavePageRequest>> requests) { - return OfflinePageBridge::CreateJavaSavePageRequests(env, - std::move(requests)); + ScopedJavaLocalRef<jclass> save_page_request_clazz = base::android::GetClass( + env, "org/chromium/chrome/browser/offlinepages/SavePageRequest"); + jobjectArray joa = env->NewObjectArray( + requests.size(), save_page_request_clazz.obj(), nullptr); + base::android::CheckException(env); + + for (size_t i = 0; i < requests.size(); ++i) { + SavePageRequest request = *(requests[i]); + ScopedJavaLocalRef<jstring> name_space = + ConvertUTF8ToJavaString(env, request.client_id().name_space); + ScopedJavaLocalRef<jstring> id = + ConvertUTF8ToJavaString(env, request.client_id().id); + ScopedJavaLocalRef<jstring> url = + ConvertUTF8ToJavaString(env, request.url().spec()); + ScopedJavaLocalRef<jstring> origin = + ConvertUTF8ToJavaString(env, request.request_origin()); + + ScopedJavaLocalRef<jobject> j_save_page_request = + Java_SavePageRequest_create( + env, static_cast<int>(request.request_state()), + request.request_id(), url, name_space, id, origin); + env->SetObjectArrayElement(joa, i, j_save_page_request.obj()); + } + + return ScopedJavaLocalRef<jobjectArray>(env, joa); } void OnGetAllRequestsDone( @@ -342,57 +384,6 @@ } // static -ScopedJavaLocalRef<jobjectArray> OfflinePageBridge::CreateJavaSavePageRequests( - JNIEnv* env, - std::vector<std::unique_ptr<SavePageRequest>> requests) { - ScopedJavaLocalRef<jclass> save_page_request_clazz = base::android::GetClass( - env, "org/chromium/chrome/browser/offlinepages/SavePageRequest"); - jobjectArray joa = env->NewObjectArray( - requests.size(), save_page_request_clazz.obj(), nullptr); - base::android::CheckException(env); - - for (size_t i = 0; i < requests.size(); ++i) { - SavePageRequest request = *(requests[i]); - ScopedJavaLocalRef<jstring> name_space = - ConvertUTF8ToJavaString(env, request.client_id().name_space); - ScopedJavaLocalRef<jstring> id = - ConvertUTF8ToJavaString(env, request.client_id().id); - ScopedJavaLocalRef<jstring> url = - ConvertUTF8ToJavaString(env, request.url().spec()); - ScopedJavaLocalRef<jstring> origin = - ConvertUTF8ToJavaString(env, request.request_origin()); - - ScopedJavaLocalRef<jobject> j_save_page_request = - Java_SavePageRequest_create( - env, static_cast<int>(request.request_state()), - request.request_id(), url, name_space, id, origin); - env->SetObjectArrayElement(joa, i, j_save_page_request.obj()); - } - - return ScopedJavaLocalRef<jobjectArray>(env, joa); -} - -// static -void OfflinePageBridge::AddOfflinePageItemsToJavaList( - JNIEnv* env, - const JavaRef<jobject>& j_result_obj, - const std::vector<OfflinePageItem>& offline_pages) { - for (const OfflinePageItem& offline_page : offline_pages) { - Java_OfflinePageBridge_createOfflinePageAndAddToList( - env, j_result_obj, - ConvertUTF8ToJavaString(env, offline_page.url.spec()), - offline_page.offline_id, - ConvertUTF8ToJavaString(env, offline_page.client_id.name_space), - ConvertUTF8ToJavaString(env, offline_page.client_id.id), - ConvertUTF16ToJavaString(env, offline_page.title), - ConvertUTF8ToJavaString(env, offline_page.file_path.value()), - offline_page.file_size, offline_page.creation_time.ToJavaTime(), - offline_page.access_count, offline_page.last_access_time.ToJavaTime(), - ConvertUTF8ToJavaString(env, offline_page.request_origin)); - } -} - -// static std::string OfflinePageBridge::GetEncodedOriginApp( const content::WebContents* web_contents) { TabAndroid* tab = TabAndroid::FromWebContents(web_contents); @@ -448,6 +439,24 @@ JNI_SavePageRequest_ToJavaDeletedPageInfo(env, page_info)); } +void OfflinePageBridge::GetAllPages( + JNIEnv* env, + const JavaParamRef<jobject>& obj, + const JavaParamRef<jobject>& j_result_obj, + const JavaParamRef<jobject>& j_callback_obj) { + DCHECK(j_result_obj); + DCHECK(j_callback_obj); + + ScopedJavaGlobalRef<jobject> j_result_ref; + j_result_ref.Reset(env, j_result_obj); + + ScopedJavaGlobalRef<jobject> j_callback_ref; + j_callback_ref.Reset(env, j_callback_obj); + + offline_page_model_->GetAllPages(base::BindOnce( + &MultipleOfflinePageItemCallback, j_result_ref, j_callback_ref)); +} + void OfflinePageBridge::GetPageByOfflineId( JNIEnv* env, const JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h index fd438c8b..70c34f42 100644 --- a/chrome/browser/offline_pages/android/offline_page_bridge.h +++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -14,7 +14,6 @@ #include "base/memory/weak_ptr.h" #include "base/supports_user_data.h" #include "components/offline_items_collection/core/launch_location.h" -#include "components/offline_pages/core/background/save_page_request.h" #include "components/offline_pages/core/offline_page_item.h" #include "components/offline_pages/core/offline_page_model.h" @@ -40,16 +39,6 @@ JNIEnv* env, const OfflinePageItem& offline_page); - static base::android::ScopedJavaLocalRef<jobjectArray> - CreateJavaSavePageRequests( - JNIEnv* env, - std::vector<std::unique_ptr<SavePageRequest>> requests); - - static void AddOfflinePageItemsToJavaList( - JNIEnv* env, - const base::android::JavaRef<jobject>& j_result_obj, - const std::vector<OfflinePageItem>& offline_pages); - static std::string GetEncodedOriginApp( const content::WebContents* web_contents); @@ -65,6 +54,11 @@ void OfflinePageDeleted( const OfflinePageModel::DeletedPageInfo& page_info) override; + void GetAllPages(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& j_result_obj, + const base::android::JavaParamRef<jobject>& j_callback_obj); + void GetPageByOfflineId( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/offline_pages/android/offline_test_util_jni.cc b/chrome/browser/offline_pages/android/offline_test_util_jni.cc deleted file mode 100644 index 58914dab..0000000 --- a/chrome/browser/offline_pages/android/offline_test_util_jni.cc +++ /dev/null
@@ -1,115 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <sstream> - -#include "base/android/callback_android.h" -#include "base/android/jni_android.h" -#include "base/android/jni_array.h" -#include "base/android/jni_string.h" -#include "base/android/jni_utils.h" -#include "base/json/json_writer.h" -#include "chrome/browser/offline_pages/android/offline_page_bridge.h" -#include "chrome/browser/offline_pages/offline_page_model_factory.h" -#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h" -#include "chrome/browser/offline_pages/request_coordinator_factory.h" -#include "chrome/browser/profiles/profile_manager.h" -#include "components/offline_pages/core/background/request_coordinator.h" -#include "components/offline_pages/core/offline_page_model.h" -#include "content/public/test/url_loader_interceptor.h" -#include "jni/OfflineTestUtil_jni.h" - -// Below is the native implementation of OfflineTestUtil.java. - -namespace offline_pages { -namespace { -using ::base::android::JavaParamRef; -using ::base::android::ScopedJavaGlobalRef; -using ::base::android::ScopedJavaLocalRef; -using ::offline_pages::android::OfflinePageBridge; - -Profile* GetProfile() { - Profile* profile = ProfileManager::GetLastUsedProfile(); - DCHECK(profile); - return profile; -} -RequestCoordinator* GetRequestCoordinator() { - return RequestCoordinatorFactory::GetForBrowserContext(GetProfile()); -} -OfflinePageModel* GetOfflinePageModel() { - return OfflinePageModelFactory::GetForBrowserContext(GetProfile()); -} - -void OnGetAllRequestsDone( - const ScopedJavaGlobalRef<jobject>& j_callback_obj, - std::vector<std::unique_ptr<SavePageRequest>> all_requests) { - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::RunObjectCallbackAndroid( - j_callback_obj, - offline_pages::android::OfflinePageBridge::CreateJavaSavePageRequests( - env, std::move(all_requests))); -} - -void OnGetAllPagesDone( - const ScopedJavaGlobalRef<jobject>& j_result_obj, - const ScopedJavaGlobalRef<jobject>& j_callback_obj, - const OfflinePageModel::MultipleOfflinePageItemResult& result) { - JNIEnv* env = base::android::AttachCurrentThread(); - OfflinePageBridge::AddOfflinePageItemsToJavaList(env, j_result_obj, result); - base::android::RunObjectCallbackAndroid(j_callback_obj, j_result_obj); -} - -void OnDeletePageDone(const ScopedJavaGlobalRef<jobject>& j_callback_obj, - OfflinePageModel::DeletePageResult result) { - base::android::RunIntCallbackAndroid(j_callback_obj, - static_cast<int>(result)); -} - -} // namespace - -void JNI_OfflineTestUtil_GetRequestsInQueue( - JNIEnv* env, - const JavaParamRef<jobject>& j_callback_obj) { - ScopedJavaGlobalRef<jobject> j_callback_ref(j_callback_obj); - - RequestCoordinator* coordinator = GetRequestCoordinator(); - - if (!coordinator) { - // Callback with null to signal that results are unavailable. - const JavaParamRef<jobject> empty_result(nullptr); - base::android::RunObjectCallbackAndroid(j_callback_obj, empty_result); - return; - } - - coordinator->GetAllRequests( - base::BindOnce(&OnGetAllRequestsDone, std::move(j_callback_ref))); -} - -void JNI_OfflineTestUtil_GetAllPages( - JNIEnv* env, - const JavaParamRef<jobject>& j_result_obj, - const JavaParamRef<jobject>& j_callback_obj) { - DCHECK(j_result_obj); - DCHECK(j_callback_obj); - - ScopedJavaGlobalRef<jobject> j_result_ref(env, j_result_obj); - ScopedJavaGlobalRef<jobject> j_callback_ref(env, j_callback_obj); - GetOfflinePageModel()->GetAllPages(base::BindOnce( - &OnGetAllPagesDone, std::move(j_result_ref), std::move(j_callback_ref))); -} - -void JNI_OfflineTestUtil_DeletePagesByOfflineId( - JNIEnv* env, - const JavaParamRef<jlongArray>& j_offline_ids_array, - const JavaParamRef<jobject>& j_callback_obj) { - ScopedJavaGlobalRef<jobject> j_callback_ref(env, j_callback_obj); - std::vector<int64_t> offline_ids; - base::android::JavaLongArrayToInt64Vector(env, j_offline_ids_array, - &offline_ids); - GetOfflinePageModel()->DeletePagesByOfflineId( - offline_ids, - base::BindOnce(&OnDeletePageDone, std::move(j_callback_ref))); -} - -} // namespace offline_pages
diff --git a/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js b/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js index 5742fb7..3e56d7d 100644 --- a/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js +++ b/chrome/browser/resources/chromeos/switch_access/keyboard_handler.js
@@ -11,15 +11,35 @@ */ constructor(switchAccess) { /** - * SwitchAccess reference. + * Switch Access reference. * @private {!SwitchAccessInterface} */ this.switchAccess_ = switchAccess; + /** @private {function(number)|undefined} */ + this.keycodeCallback_; + this.init_(); } /** + * Listens for keycodes. When they're received, they are passed to |callback|. + * @param {function(number)} callback + */ + listenForKeycodes(callback) { + this.keycodeCallback_ = callback; + chrome.accessibilityPrivate.forwardKeyEventsToSwitchAccess(true); + } + + /** + * Stop listening for keycodes. + */ + stopListeningForKeycodes() { + this.keycodeCallback_ = undefined; + chrome.accessibilityPrivate.forwardKeyEventsToSwitchAccess(false); + } + + /** * Update the keyboard keys captured by Switch Access to those stored in * prefs. */ @@ -35,12 +55,22 @@ } /** + * Forwards the current key code to the callback. + * @param {!Event} event + * @private + */ + forwardKeyCode_(event) { + if (this.keycodeCallback_) + this.keycodeCallback_(event.keyCode); + } + + /** * Run the command associated with the passed keyboard event. * * @param {!Event} event * @private */ - handleKeyEvent_(event) { + handleSwitchActivated_(event) { for (const command of this.switchAccess_.getCommands()) { if (this.keyCodeFor_(command) === event.keyCode) { this.switchAccess_.runCommand(command); @@ -56,7 +86,8 @@ */ init_() { this.updateSwitchAccessKeys(); - document.addEventListener('keyup', this.handleKeyEvent_.bind(this)); + document.addEventListener('keyup', this.handleSwitchActivated_.bind(this)); + document.addEventListener('keydown', this.forwardKeyCode_.bind(this)); } /**
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access.js b/chrome/browser/resources/chromeos/switch_access/switch_access.js index 6af5930..c548597 100644 --- a/chrome/browser/resources/chromeos/switch_access/switch_access.js +++ b/chrome/browser/resources/chromeos/switch_access/switch_access.js
@@ -134,6 +134,21 @@ } /** + * Forwards the keycodes received from keyPressed events to |callback|. + * @param {function(number)} callback + */ + listenForKeycodes(callback) { + this.keyboardHandler_.listenForKeycodes(callback); + } + + /** + * Stops forwarding keycodes. + */ + stopListeningForKeycodes() { + this.keyboardHandler_.stopListeningForKeycodes(); + } + + /** * Run the function binding for the specified command. * @override * @param {string} command
diff --git a/chrome/browser/resources/chromeos/switch_access/switch_access_interface.js b/chrome/browser/resources/chromeos/switch_access/switch_access_interface.js index c488f08..97c88ff 100644 --- a/chrome/browser/resources/chromeos/switch_access/switch_access_interface.js +++ b/chrome/browser/resources/chromeos/switch_access/switch_access_interface.js
@@ -47,6 +47,17 @@ getDefaultKeyCodeFor(command) {} /** + * Forwards keycodes received from keyPress events to |callback|. + * @param {function(number)} callback + */ + listenForKeycodes(callback) {} + + /** + * Stops forwarding keycodes. + */ + stopListeningForKeycodes() {} + + /** * Run the function binding for the specified command. * @param {string} command */
diff --git a/chrome/browser/resources/print_preview/BUILD.gn b/chrome/browser/resources/print_preview/BUILD.gn index 6e21770..94826af 100644 --- a/chrome/browser/resources/print_preview/BUILD.gn +++ b/chrome/browser/resources/print_preview/BUILD.gn
@@ -74,11 +74,6 @@ } js_library("print_preview_utils") { - deps = [ - "data:coordinate2d", - "data:size", - "//ui/webui/resources/js:cr", - ] } js_library("metrics") {
diff --git a/chrome/browser/resources/print_preview/data/BUILD.gn b/chrome/browser/resources/print_preview/data/BUILD.gn index 3d9fdb7d..3b7b082 100644 --- a/chrome/browser/resources/print_preview/data/BUILD.gn +++ b/chrome/browser/resources/print_preview/data/BUILD.gn
@@ -78,7 +78,6 @@ js_library("destination") { deps = [ - "..:print_preview_utils", "//ui/webui/resources/js:cr", "//ui/webui/resources/js:load_time_data", ]
diff --git a/chrome/browser/resources/print_preview/data/cloud_parsers.js b/chrome/browser/resources/print_preview/data/cloud_parsers.js index 4069b25..2648923 100644 --- a/chrome/browser/resources/print_preview/data/cloud_parsers.js +++ b/chrome/browser/resources/print_preview/data/cloud_parsers.js
@@ -111,7 +111,7 @@ const optionalParams = { account: account, tags: tags, - isOwned: arrayContains(tags, OWNED_TAG), + isOwned: tags.includes(OWNED_TAG), lastAccessTime: parseInt(json[CloudDestinationField.LAST_ACCESS], 10) || Date.now(), cloudID: id, @@ -121,7 +121,7 @@ const cloudDest = new print_preview.Destination( id, parseType(json[CloudDestinationField.TYPE]), origin, json[CloudDestinationField.DISPLAY_NAME], - arrayContains(tags, RECENT_TAG) /*isRecent*/, connectionStatus, + tags.includes(RECENT_TAG) /*isRecent*/, connectionStatus, optionalParams); if (json.hasOwnProperty(CloudDestinationField.CAPABILITIES)) { cloudDest.capabilities = /** @type {!print_preview.Cdd} */ (
diff --git a/chrome/browser/resources/print_preview/data/destination.js b/chrome/browser/resources/print_preview/data/destination.js index 5580239c5..6b0cfaec 100644 --- a/chrome/browser/resources/print_preview/data/destination.js +++ b/chrome/browser/resources/print_preview/data/destination.js
@@ -607,12 +607,10 @@ /** @return {boolean} Whether the destination is considered offline. */ get isOffline() { - return arrayContains( - [ - print_preview.DestinationConnectionStatus.OFFLINE, - print_preview.DestinationConnectionStatus.DORMANT - ], - this.connectionStatus_); + return [ + print_preview.DestinationConnectionStatus.OFFLINE, + print_preview.DestinationConnectionStatus.DORMANT + ].includes(this.connectionStatus_); } /**
diff --git a/chrome/browser/resources/print_preview/data/destination_match.js b/chrome/browser/resources/print_preview/data/destination_match.js index be030065..e30339c 100644 --- a/chrome/browser/resources/print_preview/data/destination_match.js +++ b/chrome/browser/resources/print_preview/data/destination_match.js
@@ -51,16 +51,17 @@ } /** - * @param {string} origin Origin to match. + * @param {!print_preview.DestinationOrigin} origin Origin to match. * @return {boolean} Whether the origin is one of the {@code origins_}. */ matchOrigin(origin) { - return arrayContains(this.origins_, origin); + return this.origins_.includes(origin); } /** * @param {string} id Id of the destination. - * @param {string} origin Origin of the destination. + * @param {!print_preview.DestinationOrigin} origin Origin of the + * destination. * @return {boolean} Whether destination is the same as initial. */ matchIdAndOrigin(id, origin) { @@ -98,13 +99,11 @@ * @private */ isVirtualDestination_(destination) { - if (destination.origin == print_preview.DestinationOrigin.LOCAL) { - return arrayContains( - [print_preview.Destination.GooglePromotedId.SAVE_AS_PDF], - destination.id); + if (destination.origin === print_preview.DestinationOrigin.LOCAL) { + return destination.id === + print_preview.Destination.GooglePromotedId.SAVE_AS_PDF; } - return arrayContains( - [print_preview.Destination.GooglePromotedId.DOCS], destination.id); + return destination.id === print_preview.Destination.GooglePromotedId.DOCS; } /**
diff --git a/chrome/browser/resources/print_preview/new/BUILD.gn b/chrome/browser/resources/print_preview/new/BUILD.gn index 9c71426..f4951f2a 100644 --- a/chrome/browser/resources/print_preview/new/BUILD.gn +++ b/chrome/browser/resources/print_preview/new/BUILD.gn
@@ -108,6 +108,7 @@ deps = [ ":input_behavior", ":settings_behavior", + "..:print_preview_utils", "//ui/webui/resources/cr_elements/cr_input:cr_input", "//ui/webui/resources/js:load_time_data", ] @@ -241,7 +242,6 @@ ":settings_behavior", ":state", "..:native_layer", - "..:print_preview_utils", "../../pdf:pdf_scripting_api", "../data:coordinate2d", "../data:destination",
diff --git a/chrome/browser/resources/print_preview/new/preview_area.html b/chrome/browser/resources/print_preview/new/preview_area.html index baeebf38..abda42d 100644 --- a/chrome/browser/resources/print_preview/new/preview_area.html +++ b/chrome/browser/resources/print_preview/new/preview_area.html
@@ -8,7 +8,6 @@ <link rel="import" href="chrome://resources/html/util.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="../native_layer.html"> -<link rel="import" href="../print_preview_utils.html"> <link rel="import" href="../data/coordinate2d.html"> <link rel="import" href="../data/destination.html"> <link rel="import" href="../data/margins.html">
diff --git a/chrome/browser/resources/print_preview/print_preview_utils.html b/chrome/browser/resources/print_preview/print_preview_utils.html index 8daa3afe..1e8d2bd8 100644 --- a/chrome/browser/resources/print_preview/print_preview_utils.html +++ b/chrome/browser/resources/print_preview/print_preview_utils.html
@@ -1,5 +1 @@ -<link rel="import" href="chrome://resources/html/cr.html"> -<link rel="import" href="data/coordinate2d.html"> -<link rel="import" href="data/size.html"> - <script src="print_preview_utils.js"></script>
diff --git a/chrome/browser/resources/print_preview/print_preview_utils.js b/chrome/browser/resources/print_preview/print_preview_utils.js index 7fbc963..a17e8f62 100644 --- a/chrome/browser/resources/print_preview/print_preview_utils.js +++ b/chrome/browser/resources/print_preview/print_preview_utils.js
@@ -3,46 +3,9 @@ // found in the LICENSE file. /** - * @param {string} toTest The string to be tested. - * @return {boolean} True if |toTest| contains only digits. Leading and trailing - * whitespace is allowed. - */ -function isInteger(toTest) { - const numericExp = /^\s*[0-9]+\s*$/; - return numericExp.test(toTest); -} - -/** - * Returns true if |value| is a valid non zero positive integer. - * @param {string} value The string to be tested. - * @return {boolean} true if the |value| is valid non zero positive integer. - */ -function isPositiveInteger(value) { - return isInteger(value) && parseInt(value, 10) > 0; -} - -/** - * Returns true if the contents of the two arrays are equal. - * @param {Array<{from: number, to: number}>} array1 The first array. - * @param {Array<{from: number, to: number}>} array2 The second array. - * @return {boolean} true if the arrays are equal. - */ -function areArraysEqual(array1, array2) { - if (array1.length != array2.length) { - return false; - } - for (let i = 0; i < array1.length; i++) { - if (array1[i] !== array2[i]) { - return false; - } - } - return true; -} - -/** * Returns true if the contents of the two page ranges are equal. - * @param {Array} array1 The first array. - * @param {Array} array2 The second array. + * @param {!Array<{ to: number, from: number }>} array1 The first array. + * @param {!Array<{ to: number, from: number }>} array2 The second array. * @return {boolean} true if the arrays are equal. */ function areRangesEqual(array1, array2) { @@ -58,179 +21,6 @@ } /** - * Removes duplicate elements from |inArray| and returns a new array. - * |inArray| is not affected. It assumes that |inArray| is already sorted. - * @param {!Array<number>} inArray The array to be processed. - * @return {!Array<number>} The array after processing. - */ -function removeDuplicates(inArray) { - const out = []; - - if (inArray.length == 0) { - return out; - } - - out.push(inArray[0]); - for (let i = 1; i < inArray.length; ++i) { - if (inArray[i] != inArray[i - 1]) { - out.push(inArray[i]); - } - } - return out; -} - -/** @enum {number} */ -const PageRangeStatus = { - NO_ERROR: 0, - SYNTAX_ERROR: -1, - LIMIT_ERROR: -2 -}; - -/** - * Returns a list of ranges in |pageRangeText|. The ranges are - * listed in the order they appear in |pageRangeText| and duplicates are not - * eliminated. If |pageRangeText| is not valid, PageRangeStatus.SYNTAX_ERROR - * is returned. - * A valid selection has a parsable format and every page identifier is - * greater than 0 unless wildcards are used(see examples). - * If a page is greater than |totalPageCount|, PageRangeStatus.LIMIT_ERROR - * is returned. - * If |totalPageCount| is 0 or undefined function uses impossibly large number - * instead. - * Wildcard the first number must be larger than 0 and less or equal then - * |totalPageCount|. If it's missed then 1 is used as the first number. - * Wildcard the second number must be larger then the first number. If it's - * missed then |totalPageCount| is used as the second number. - * Example: "1-4, 9, 3-6, 10, 11" is valid, assuming |totalPageCount| >= 11. - * Example: "1-4, -6" is valid, assuming |totalPageCount| >= 6. - * Example: "2-" is valid, assuming |totalPageCount| >= 2, means from 2 to the - * end. - * Example: "4-2, 11, -6" is invalid. - * Example: "-" is valid, assuming |totalPageCount| >= 1. - * Example: "1-4dsf, 11" is invalid regardless of |totalPageCount|. - * @param {string} pageRangeText The text to be checked. - * @param {number=} opt_totalPageCount The total number of pages. - * @return {!PageRangeStatus|!Array<{from: number, to: number}>} - */ -function pageRangeTextToPageRanges(pageRangeText, opt_totalPageCount) { - if (pageRangeText == '') { - return []; - } - - const MAX_PAGE_NUMBER = 1000000000; - const totalPageCount = - opt_totalPageCount ? opt_totalPageCount : MAX_PAGE_NUMBER; - - const regex = /^\s*([0-9]*)\s*-\s*([0-9]*)\s*$/; - const parts = pageRangeText.split(/,|\u3001/); - - const pageRanges = []; - for (let i = 0; i < parts.length; ++i) { - const match = parts[i].match(regex); - if (match) { - if (!isPositiveInteger(match[1]) && match[1] !== '') { - return PageRangeStatus.SYNTAX_ERROR; - } - if (!isPositiveInteger(match[2]) && match[2] !== '') { - return PageRangeStatus.SYNTAX_ERROR; - } - const from = match[1] ? parseInt(match[1], 10) : 1; - const to = match[2] ? parseInt(match[2], 10) : totalPageCount; - if (from > to) { - return PageRangeStatus.SYNTAX_ERROR; - } - if (to > totalPageCount) { - return PageRangeStatus.LIMIT_ERROR; - } - pageRanges.push({'from': from, 'to': to}); - } else { - if (!isPositiveInteger(parts[i])) { - return PageRangeStatus.SYNTAX_ERROR; - } - const singlePageNumber = parseInt(parts[i], 10); - if (singlePageNumber > totalPageCount) { - return PageRangeStatus.LIMIT_ERROR; - } - pageRanges.push({'from': singlePageNumber, 'to': singlePageNumber}); - } - } - return pageRanges; -} - -/** - * Returns a list of pages defined by |pagesRangeText|. The pages are - * listed in the order they appear in |pageRangeText| and duplicates are not - * eliminated. If |pageRangeText| is not valid according or - * |totalPageCount| undefined [1,2,...,totalPageCount] is returned. - * See pageRangeTextToPageRanges for details. - * @param {string} pageRangeText The text to be checked. - * @param {number} totalPageCount The total number of pages. - * @return {!Array<number>} A list of all pages. - */ -function pageRangeTextToPageList(pageRangeText, totalPageCount) { - const pageRanges = pageRangeTextToPageRanges(pageRangeText, totalPageCount); - const pageList = []; - if (Array.isArray(pageRanges)) { - for (let i = 0; i < pageRanges.length; ++i) { - for (let j = pageRanges[i].from; - j <= Math.min(pageRanges[i].to, totalPageCount); ++j) { - pageList.push(j); - } - } - } - if (pageList.length == 0) { - for (let j = 1; j <= totalPageCount; ++j) { - pageList.push(j); - } - } - return pageList; -} - -/** - * @param {!Array<number>} pageList The list to be processed. - * @return {!Array<number>} The contents of |pageList| in ascending order and - * without any duplicates. |pageList| is not affected. - */ -function pageListToPageSet(pageList) { - let pageSet = []; - if (pageList.length == 0) { - return pageSet; - } - pageSet = pageList.slice(0); - pageSet.sort(function(a, b) { - return /** @type {number} */ (a) - /** @type {number} */ (b); - }); - pageSet = removeDuplicates(pageSet); - return pageSet; -} - -/** - * @param {!HTMLElement} element Element to check for visibility. - * @return {boolean} Whether the given element is visible. - */ -function getIsVisible(element) { - return !element.hidden; -} - -/** - * Shows or hides an element. - * @param {!HTMLElement} element Element to show or hide. - * @param {boolean} isVisible Whether the element should be visible or not. - */ -function setIsVisible(element, isVisible) { - element.hidden = !isVisible; -} - -/** - * @param {!Array} array Array to check for item. - * @param {*} item Item to look for in array. - * @return {boolean} Whether the item is in the array. - */ -function arrayContains(array, item) { - return array.indexOf(item) != -1; -} - -/** * @param {!Array<!{locale: string, value: string}>} localizedStrings An array * of strings with corresponding locales. * @param {string} locale Locale to look the string up for.
diff --git a/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs b/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs deleted file mode 100644 index 17fa25be..0000000 --- a/chrome/browser/resources/print_preview/print_preview_utils_unittest.gtestjs +++ /dev/null
@@ -1,139 +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. - -/** - * Test fixture for print preview utils. - * @constructor - * @extends {testing.Test} - */ -function PrintPreviewUtilsUnitTest () { - testing.Test.call(this); -} - -PrintPreviewUtilsUnitTest.prototype = { - __proto__: testing.Test.prototype, - - /** @override */ - extraLibraries: [ - 'print_preview_utils.js', - ] -}; - -TEST_F('PrintPreviewUtilsUnitTest', 'IsInteger', function() { - assertFalse(isInteger(" abc ")); - assertFalse(isInteger("-7")); - assertFalse(isInteger("7.0")); - assertFalse(isInteger("a7a")); - - assertTrue(isInteger("0")); - assertTrue(isInteger(" 100 ")); - assertTrue(isInteger("0055 ")); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'IsPositiveInteger', function() { - assertTrue(isPositiveInteger("100")); - assertTrue(isPositiveInteger("0055")); - - assertFalse(isPositiveInteger("0")); - assertFalse(isPositiveInteger("-100")); - assertFalse(isPositiveInteger("sdfs")); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'AreArraysEqual', function() { - assertTrue(areArraysEqual([2,4,6,8,10], [2,4,6,8,10])); - assertTrue(areArraysEqual([], [])); - - assertFalse(areArraysEqual([2,4,6,8,10,12], [2,4,6,8,10])); - assertFalse(areArraysEqual([], [2,4,6,8,10])); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'RemoveDuplicates', function() { - var array1 = [1,2,2,3,6,6,6,7,9,10]; - assertTrue(areArraysEqual(removeDuplicates(array1), [1,2,3,6,7,9,10])); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'PageRanges', function() { - function assertRangesEqual(simpleRange1, range2) { - var range1 = [] - for (var i = 0; i < simpleRange1.length; i++) { - var from; - var to; - if (Array.isArray(simpleRange1[i])) { - from = simpleRange1[i][0]; - to = simpleRange1[i][1]; - } else { - from = simpleRange1[i]; - to = simpleRange1[i]; - } - range1.push({'from': from, 'to': to}); - } - assertTrue(areRangesEqual(range1, range2)); - }; - assertRangesEqual([1, 2, 3, 1, 56], - pageRangeTextToPageRanges("1,2,3,1,56", 100)); - assertRangesEqual([[1, 3],[6, 9], [6, 10]], - pageRangeTextToPageRanges("1-3, 6-9,6-10 ", 100)); - assertRangesEqual([[10, 100]], - pageRangeTextToPageRanges("10-", 100)); - assertRangesEqual([[10, 100000]], - pageRangeTextToPageRanges("10-100000", 100000)); - assertRangesEqual([[1, 100]], - pageRangeTextToPageRanges("-", 100)); - assertRangesEqual([1, 2], - pageRangeTextToPageRanges("1,2", undefined)); - assertRangesEqual([[1, 1000000000]], - pageRangeTextToPageRanges("-", null)); - assertRangesEqual([[1, 1000000000]], - pageRangeTextToPageRanges("-", 0)); - - // https://crbug.com/806165 - assertRangesEqual([1, 2, 3, 1, 56], - pageRangeTextToPageRanges("1\u30012\u30013\u30011\u300156", 100)); - assertRangesEqual([1, 2, 3, 1, 56], - pageRangeTextToPageRanges("1,2,3\u30011\u300156", 100)); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'InvalidPageRanges', function() { - assertEquals(PageRangeStatus.LIMIT_ERROR, - pageRangeTextToPageRanges("10-100000", 100)); - assertEquals(PageRangeStatus.LIMIT_ERROR, - pageRangeTextToPageRanges("1,100000", 100)); - assertEquals(PageRangeStatus.SYNTAX_ERROR, - pageRangeTextToPageRanges("1,2,0,56", 100)); - assertEquals(PageRangeStatus.SYNTAX_ERROR, - pageRangeTextToPageRanges("-1,1,2,,56", 100)); - assertEquals(PageRangeStatus.SYNTAX_ERROR, - pageRangeTextToPageRanges("1,2,56-40", 100)); - assertEquals(PageRangeStatus.LIMIT_ERROR, - pageRangeTextToPageRanges("101-110", 100)); - - assertEquals(PageRangeStatus.SYNTAX_ERROR, - pageRangeTextToPageRanges("1\u30012\u30010\u300156", 100)); - assertEquals(PageRangeStatus.SYNTAX_ERROR, - pageRangeTextToPageRanges("-1,1,2\u3001\u300156", 100)); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'PageRangeTextToPageList', function() { - assertTrue(areArraysEqual([1], - pageRangeTextToPageList("1", 10))); - assertTrue(areArraysEqual([1,2,3,4], - pageRangeTextToPageList("1-4", 10))); - assertTrue(areArraysEqual([1,2,3,4,2,3,4], - pageRangeTextToPageList("1-4, 2-4", 10))); - assertTrue(areArraysEqual([1,2,5,7,8,9,10,2,2,3], - pageRangeTextToPageList("1-2, 5, 7-10, 2, 2, 3", - 10))); - assertTrue(areArraysEqual([5,6,7,8,9,10], - pageRangeTextToPageList("5-", 10))); - assertTrue(areArraysEqual([], - pageRangeTextToPageList("1-4", undefined))); - assertTrue(areArraysEqual([1,2,3,4,5,6,7,8,9,10], - pageRangeTextToPageList("1-abcd", 10))); -}); - -TEST_F('PrintPreviewUtilsUnitTest', 'PageListToPageSet', function() { - assertTrue(areArraysEqual([1,2,3,4], pageListToPageSet([4,3,2,1,1,1]))); - assertTrue(areArraysEqual([1,2,3,4], pageListToPageSet([1,2,2,3,4,1,1,1]))); - assertTrue(areArraysEqual([], pageListToPageSet([]))); -});
diff --git a/chrome/browser/resources/settings/people_page/account_manager.html b/chrome/browser/resources/settings/people_page/account_manager.html index 0c996154..1dea615 100644 --- a/chrome/browser/resources/settings/people_page/account_manager.html +++ b/chrome/browser/resources/settings/people_page/account_manager.html
@@ -32,6 +32,17 @@ #add-account-button { cursor: pointer; } + + #error-badge { + left: 60%; + position: relative; + top: 60%; + } + + :host-context([dir='rtl']) #error-badge { + left: auto; + right: 60%; + } </style> <div class="settings-box first">$i18n{accountManagerDescription}</div> @@ -45,7 +56,11 @@ <div class="settings-box"> <div class="profile-icon" - style="background-image: [[getIconImageSet_(item.pic)]]"></div> + style="background-image: [[getIconImageSet_(item.pic)]]"> + <template is="dom-if" if="[[!item.isSignedIn]]"> + <img id="error-badge" src="chrome://resources/images/error_badge.svg"> + </template> + </div> <div class="middle two-line no-min-width"> <div class="flex text-elide">
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 5fdc5156..79395b0 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -99,6 +99,8 @@ "safe_browsing_service.cc", "safe_browsing_service.h", "services_delegate.h", + "telemetry/telemetry_service.cc", + "telemetry/telemetry_service.h", "test_safe_browsing_blocking_page_quiet.cc", "test_safe_browsing_blocking_page_quiet.h", "trigger_creator.cc", @@ -208,8 +210,8 @@ "incident_reporting/state_store.h", "incident_reporting/tracked_preference_incident.cc", "incident_reporting/tracked_preference_incident.h", - "services_delegate_impl.cc", - "services_delegate_impl.h", + "services_delegate_desktop.cc", + "services_delegate_desktop.h", "signature_evaluator_mac.h", "signature_evaluator_mac.mm", ] @@ -233,8 +235,10 @@ sources += [ "../loader/safe_browsing_resource_throttle.cc", "../loader/safe_browsing_resource_throttle.h", - "services_delegate_stub.cc", - "services_delegate_stub.h", + "android/services_delegate_android.cc", + "android/services_delegate_android.h", + "telemetry/android/android_telemetry_service.cc", + "telemetry/android/android_telemetry_service.h", ] deps += [ "//components/safe_browsing/android:safe_browsing_mobile" ] }
diff --git a/chrome/browser/safe_browsing/android/services_delegate_android.cc b/chrome/browser/safe_browsing/android/services_delegate_android.cc new file mode 100644 index 0000000..0dc7844 --- /dev/null +++ b/chrome/browser/safe_browsing/android/services_delegate_android.cc
@@ -0,0 +1,133 @@ +// 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/safe_browsing/android/services_delegate_android.h" + +#include "base/logging.h" +#include "base/memory/ptr_util.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h" +#include "chrome/browser/safe_browsing/telemetry/telemetry_service.h" +#include "components/safe_browsing/android/remote_database_manager.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/download_manager.h" +#include "services/network/public/cpp/shared_url_loader_factory.h" +#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h" + +namespace safe_browsing { + +// static +std::unique_ptr<ServicesDelegate> ServicesDelegate::Create( + SafeBrowsingService* safe_browsing_service) { + return base::WrapUnique(new ServicesDelegateAndroid(safe_browsing_service)); +} + +// static +std::unique_ptr<ServicesDelegate> ServicesDelegate::CreateForTest( + SafeBrowsingService* safe_browsing_service, + ServicesDelegate::ServicesCreator* services_creator) { + NOTREACHED(); + return base::WrapUnique(new ServicesDelegateAndroid(safe_browsing_service)); +} + +ServicesDelegateAndroid::ServicesDelegateAndroid( + SafeBrowsingService* safe_browsing_service) + : safe_browsing_service_(safe_browsing_service) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} + +ServicesDelegateAndroid::~ServicesDelegateAndroid() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +} + +void ServicesDelegateAndroid::InitializeCsdService( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {} + +const scoped_refptr<SafeBrowsingDatabaseManager>& +ServicesDelegateAndroid::database_manager() const { + return database_manager_; +} + +void ServicesDelegateAndroid::Initialize() { + if (!database_manager_set_for_tests_) { + database_manager_ = + base::WrapRefCounted(new RemoteSafeBrowsingDatabaseManager()); + } +} +void ServicesDelegateAndroid::SetDatabaseManagerForTest( + SafeBrowsingDatabaseManager* database_manager) { + database_manager_set_for_tests_ = true; + database_manager_ = database_manager; +} + +void ServicesDelegateAndroid::ShutdownServices() {} + +void ServicesDelegateAndroid::RefreshState(bool enable) {} + +void ServicesDelegateAndroid::ProcessResourceRequest( + const ResourceRequestInfo* request) {} + +std::unique_ptr<prefs::mojom::TrackedPreferenceValidationDelegate> +ServicesDelegateAndroid::CreatePreferenceValidationDelegate(Profile* profile) { + return nullptr; +} + +void ServicesDelegateAndroid::RegisterDelayedAnalysisCallback( + const DelayedAnalysisCallback& callback) {} + +void ServicesDelegateAndroid::AddDownloadManager( + content::DownloadManager* download_manager) {} + +ClientSideDetectionService* ServicesDelegateAndroid::GetCsdService() { + return nullptr; +} + +DownloadProtectionService* ServicesDelegateAndroid::GetDownloadService() { + return nullptr; +} + +void ServicesDelegateAndroid::StartOnIOThread( + scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, + const V4ProtocolConfig& v4_config) { + database_manager_->StartOnIOThread(url_loader_factory, v4_config); +} + +void ServicesDelegateAndroid::StopOnIOThread(bool shutdown) { + database_manager_->StopOnIOThread(shutdown); +} + +void ServicesDelegateAndroid::CreatePasswordProtectionService( + Profile* profile) {} +void ServicesDelegateAndroid::RemovePasswordProtectionService( + Profile* profile) {} +PasswordProtectionService* +ServicesDelegateAndroid::GetPasswordProtectionService(Profile* profile) const { + NOTIMPLEMENTED(); + return nullptr; +} + +void ServicesDelegateAndroid::CreateTelemetryService(Profile* profile) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + DCHECK(profile); + + if (profile->IsOffTheRecord()) { + return; + } + + telemetry_service_ = std::make_unique<AndroidTelemetryService>( + safe_browsing_service_, profile); +} + +void ServicesDelegateAndroid::RemoveTelemetryService() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + telemetry_service_.release(); +} + +TelemetryService* ServicesDelegateAndroid::GetTelemetryService() const { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + return telemetry_service_.get(); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/services_delegate_stub.h b/chrome/browser/safe_browsing/android/services_delegate_android.h similarity index 66% rename from chrome/browser/safe_browsing/services_delegate_stub.h rename to chrome/browser/safe_browsing/android/services_delegate_android.h index d86dce84..216fcce 100644 --- a/chrome/browser/safe_browsing/services_delegate_stub.h +++ b/chrome/browser/safe_browsing/android/services_delegate_android.h
@@ -2,19 +2,23 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_STUB_H_ -#define CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_STUB_H_ +#ifndef CHROME_BROWSER_SAFE_BROWSING_ANDROID_SERVICES_DELEGATE_ANDROID_H_ +#define CHROME_BROWSER_SAFE_BROWSING_ANDROID_SERVICES_DELEGATE_ANDROID_H_ #include "base/macros.h" #include "chrome/browser/safe_browsing/services_delegate.h" namespace safe_browsing { -// Dummy ServicesDelegate implementation. Create via ServicesDelegate::Create(). -class ServicesDelegateStub : public ServicesDelegate { +class AndroidTelemetryService; +class TelemetryService; + +// Android ServicesDelegate implementation. Create via +// ServicesDelegate::Create(). +class ServicesDelegateAndroid : public ServicesDelegate { public: - ServicesDelegateStub(); - ~ServicesDelegateStub() override; + explicit ServicesDelegateAndroid(SafeBrowsingService* safe_browsing_service); + ~ServicesDelegateAndroid() override; private: // ServicesDelegate: @@ -45,13 +49,22 @@ PasswordProtectionService* GetPasswordProtectionService( Profile* profile) const override; + void CreateTelemetryService(Profile* profile) override; + void RemoveTelemetryService() override; + TelemetryService* GetTelemetryService() const override; + + SafeBrowsingService* const safe_browsing_service_; + + // The telemetry service tied to the current profile. + std::unique_ptr<AndroidTelemetryService> telemetry_service_; + scoped_refptr<SafeBrowsingDatabaseManager> database_manager_; // Has the database_manager been set for tests? bool database_manager_set_for_tests_ = false; - DISALLOW_COPY_AND_ASSIGN(ServicesDelegateStub); + DISALLOW_COPY_AND_ASSIGN(ServicesDelegateAndroid); }; } // namespace safe_browsing -#endif // CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_STUB_H_ +#endif // CHROME_BROWSER_SAFE_BROWSING_ANDROID_SERVICES_DELEGATE_ANDROID_H_
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc index 4468b5c6..d22ce50 100644 --- a/chrome/browser/safe_browsing/safe_browsing_service.cc +++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -454,6 +454,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); Profile* profile = content::Source<Profile>(source).ptr(); services_delegate_->CreatePasswordProtectionService(profile); + services_delegate_->CreateTelemetryService(profile); if (!profile->IsOffTheRecord()) AddPrefService(profile->GetPrefs()); break; @@ -462,6 +463,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); Profile* profile = content::Source<Profile>(source).ptr(); services_delegate_->RemovePasswordProtectionService(profile); + services_delegate_->RemoveTelemetryService(); if (!profile->IsOffTheRecord()) RemovePrefService(profile->GetPrefs()); break;
diff --git a/chrome/browser/safe_browsing/services_delegate.h b/chrome/browser/safe_browsing/services_delegate.h index e880de68..b474840 100644 --- a/chrome/browser/safe_browsing/services_delegate.h +++ b/chrome/browser/safe_browsing/services_delegate.h
@@ -36,6 +36,7 @@ struct ResourceRequestInfo; class SafeBrowsingService; class SafeBrowsingDatabaseManager; +class TelemetryService; struct V4ProtocolConfig; // Abstraction to help organize code for mobile vs full safe browsing modes. @@ -117,6 +118,10 @@ virtual void RemovePasswordProtectionService(Profile* profile) = 0; virtual PasswordProtectionService* GetPasswordProtectionService( Profile* profile) const = 0; + + virtual void CreateTelemetryService(Profile* profile) = 0; + virtual void RemoveTelemetryService() = 0; + virtual TelemetryService* GetTelemetryService() const = 0; }; } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/services_delegate_impl.cc b/chrome/browser/safe_browsing/services_delegate_desktop.cc similarity index 74% rename from chrome/browser/safe_browsing/services_delegate_impl.cc rename to chrome/browser/safe_browsing/services_delegate_desktop.cc index 37099457..1eb00c0 100644 --- a/chrome/browser/safe_browsing/services_delegate_impl.cc +++ b/chrome/browser/safe_browsing/services_delegate_desktop.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/safe_browsing/services_delegate_impl.h" +#include "chrome/browser/safe_browsing/services_delegate_desktop.h" #include <utility> @@ -10,6 +10,7 @@ #include "base/memory/ptr_util.h" #include "base/strings/string_util.h" #include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "chrome/browser/safe_browsing/telemetry/telemetry_service.h" #include "chrome/common/chrome_switches.h" #include "components/safe_browsing/db/v4_local_database_manager.h" #include "content/public/browser/browser_thread.h" @@ -22,7 +23,7 @@ std::unique_ptr<ServicesDelegate> ServicesDelegate::Create( SafeBrowsingService* safe_browsing_service) { return base::WrapUnique( - new ServicesDelegateImpl(safe_browsing_service, nullptr)); + new ServicesDelegateDesktop(safe_browsing_service, nullptr)); } // static @@ -30,10 +31,10 @@ SafeBrowsingService* safe_browsing_service, ServicesDelegate::ServicesCreator* services_creator) { return base::WrapUnique( - new ServicesDelegateImpl(safe_browsing_service, services_creator)); + new ServicesDelegateDesktop(safe_browsing_service, services_creator)); } -ServicesDelegateImpl::ServicesDelegateImpl( +ServicesDelegateDesktop::ServicesDelegateDesktop( SafeBrowsingService* safe_browsing_service, ServicesDelegate::ServicesCreator* services_creator) : safe_browsing_service_(safe_browsing_service), @@ -41,11 +42,11 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -ServicesDelegateImpl::~ServicesDelegateImpl() { +ServicesDelegateDesktop::~ServicesDelegateDesktop() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); } -void ServicesDelegateImpl::InitializeCsdService( +void ServicesDelegateDesktop::InitializeCsdService( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); #if defined(SAFE_BROWSING_CSD) @@ -57,16 +58,16 @@ } ExtendedReportingLevel -ServicesDelegateImpl::GetEstimatedExtendedReportingLevel() const { +ServicesDelegateDesktop::GetEstimatedExtendedReportingLevel() const { return safe_browsing_service_->estimated_extended_reporting_by_prefs(); } const scoped_refptr<SafeBrowsingDatabaseManager>& -ServicesDelegateImpl::database_manager() const { +ServicesDelegateDesktop::database_manager() const { return database_manager_; } -void ServicesDelegateImpl::Initialize() { +void ServicesDelegateDesktop::Initialize() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (!database_manager_set_for_tests_) { @@ -93,14 +94,14 @@ : CreateResourceRequestDetector()); } -void ServicesDelegateImpl::SetDatabaseManagerForTest( +void ServicesDelegateDesktop::SetDatabaseManagerForTest( SafeBrowsingDatabaseManager* database_manager_to_set) { DCHECK(!database_manager_); database_manager_set_for_tests_ = true; database_manager_ = database_manager_to_set; } -void ServicesDelegateImpl::ShutdownServices() { +void ServicesDelegateDesktop::ShutdownServices() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); // The IO thread is going away, so make sure the ClientSideDetectionService // dtor executes now since it may call the dtor of URLFetcher which relies @@ -117,7 +118,7 @@ download_service_.reset(); } -void ServicesDelegateImpl::RefreshState(bool enable) { +void ServicesDelegateDesktop::RefreshState(bool enable) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (csd_service_) csd_service_->SetEnabledAndRefreshState(enable); @@ -125,7 +126,7 @@ download_service_->SetEnabled(enable); } -void ServicesDelegateImpl::ProcessResourceRequest( +void ServicesDelegateDesktop::ProcessResourceRequest( const ResourceRequestInfo* request) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); if (resource_request_detector_) @@ -133,68 +134,70 @@ } std::unique_ptr<prefs::mojom::TrackedPreferenceValidationDelegate> -ServicesDelegateImpl::CreatePreferenceValidationDelegate(Profile* profile) { +ServicesDelegateDesktop::CreatePreferenceValidationDelegate(Profile* profile) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return incident_service_->CreatePreferenceValidationDelegate(profile); } -void ServicesDelegateImpl::RegisterDelayedAnalysisCallback( +void ServicesDelegateDesktop::RegisterDelayedAnalysisCallback( const DelayedAnalysisCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); incident_service_->RegisterDelayedAnalysisCallback(callback); } -void ServicesDelegateImpl::AddDownloadManager( +void ServicesDelegateDesktop::AddDownloadManager( content::DownloadManager* download_manager) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); incident_service_->AddDownloadManager(download_manager); } -ClientSideDetectionService* ServicesDelegateImpl::GetCsdService() { +ClientSideDetectionService* ServicesDelegateDesktop::GetCsdService() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return csd_service_.get(); } -DownloadProtectionService* ServicesDelegateImpl::GetDownloadService() { +DownloadProtectionService* ServicesDelegateDesktop::GetDownloadService() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); return download_service_.get(); } scoped_refptr<SafeBrowsingDatabaseManager> -ServicesDelegateImpl::CreateDatabaseManager() { +ServicesDelegateDesktop::CreateDatabaseManager() { return V4LocalDatabaseManager::Create( SafeBrowsingService::GetBaseFilename(), base::BindRepeating( - &ServicesDelegateImpl::GetEstimatedExtendedReportingLevel, + &ServicesDelegateDesktop::GetEstimatedExtendedReportingLevel, base::Unretained(this))); } DownloadProtectionService* -ServicesDelegateImpl::CreateDownloadProtectionService() { +ServicesDelegateDesktop::CreateDownloadProtectionService() { return new DownloadProtectionService(safe_browsing_service_); } IncidentReportingService* -ServicesDelegateImpl::CreateIncidentReportingService() { +ServicesDelegateDesktop::CreateIncidentReportingService() { return new IncidentReportingService(safe_browsing_service_); } -ResourceRequestDetector* ServicesDelegateImpl::CreateResourceRequestDetector() { +ResourceRequestDetector* +ServicesDelegateDesktop::CreateResourceRequestDetector() { return new ResourceRequestDetector(safe_browsing_service_->database_manager(), incident_service_->GetIncidentReceiver()); } -void ServicesDelegateImpl::StartOnIOThread( +void ServicesDelegateDesktop::StartOnIOThread( scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, const V4ProtocolConfig& v4_config) { database_manager_->StartOnIOThread(url_loader_factory, v4_config); } -void ServicesDelegateImpl::StopOnIOThread(bool shutdown) { +void ServicesDelegateDesktop::StopOnIOThread(bool shutdown) { database_manager_->StopOnIOThread(shutdown); } -void ServicesDelegateImpl::CreatePasswordProtectionService(Profile* profile) { +void ServicesDelegateDesktop::CreatePasswordProtectionService( + Profile* profile) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile); auto it = password_protection_service_map_.find(profile); @@ -205,7 +208,8 @@ password_protection_service_map_[profile] = std::move(service); } -void ServicesDelegateImpl::RemovePasswordProtectionService(Profile* profile) { +void ServicesDelegateDesktop::RemovePasswordProtectionService( + Profile* profile) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK(profile); auto it = password_protection_service_map_.find(profile); @@ -213,12 +217,23 @@ password_protection_service_map_.erase(it); } -PasswordProtectionService* ServicesDelegateImpl::GetPasswordProtectionService( - Profile* profile) const { +PasswordProtectionService* +ServicesDelegateDesktop::GetPasswordProtectionService(Profile* profile) const { DCHECK(profile); auto it = password_protection_service_map_.find(profile); return it != password_protection_service_map_.end() ? it->second.get() : nullptr; } +// Only implemented on Android. +void ServicesDelegateDesktop::CreateTelemetryService(Profile* profile) {} + +// Only implemented on Android. +void ServicesDelegateDesktop::RemoveTelemetryService() {} + +// Only meaningful on Android. +TelemetryService* ServicesDelegateDesktop::GetTelemetryService() const { + return nullptr; +} + } // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/services_delegate_impl.h b/chrome/browser/safe_browsing/services_delegate_desktop.h similarity index 85% rename from chrome/browser/safe_browsing/services_delegate_impl.h rename to chrome/browser/safe_browsing/services_delegate_desktop.h index 6faa7b9..62223a1 100644 --- a/chrome/browser/safe_browsing/services_delegate_impl.h +++ b/chrome/browser/safe_browsing/services_delegate_desktop.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_IMPL_H_ -#define CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_IMPL_H_ +#ifndef CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_DESKTOP_H_ +#define CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_DESKTOP_H_ #include <memory> @@ -23,11 +23,11 @@ // Actual ServicesDelegate implementation. Create via // ServicesDelegate::Create(). -class ServicesDelegateImpl : public ServicesDelegate { +class ServicesDelegateDesktop : public ServicesDelegate { public: - ServicesDelegateImpl(SafeBrowsingService* safe_browsing_service, - ServicesDelegate::ServicesCreator* services_creator); - ~ServicesDelegateImpl() override; + ServicesDelegateDesktop(SafeBrowsingService* safe_browsing_service, + ServicesDelegate::ServicesCreator* services_creator); + ~ServicesDelegateDesktop() override; private: // ServicesDelegate: @@ -72,6 +72,10 @@ PasswordProtectionService* GetPasswordProtectionService( Profile* profile) const override; + void CreateTelemetryService(Profile* profile) override; + void RemoveTelemetryService() override; + TelemetryService* GetTelemetryService() const override; + std::unique_ptr<ClientSideDetectionService> csd_service_; std::unique_ptr<DownloadProtectionService> download_service_; std::unique_ptr<IncidentReportingService> incident_service_; @@ -93,9 +97,9 @@ std::map<Profile*, std::unique_ptr<ChromePasswordProtectionService>> password_protection_service_map_; - DISALLOW_COPY_AND_ASSIGN(ServicesDelegateImpl); + DISALLOW_COPY_AND_ASSIGN(ServicesDelegateDesktop); }; } // namespace safe_browsing -#endif // CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_IMPL_H_ +#endif // CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_DESKTOP_H_
diff --git a/chrome/browser/safe_browsing/services_delegate_stub.cc b/chrome/browser/safe_browsing/services_delegate_stub.cc deleted file mode 100644 index a542627..0000000 --- a/chrome/browser/safe_browsing/services_delegate_stub.cc +++ /dev/null
@@ -1,97 +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/safe_browsing/services_delegate_stub.h" - -#include "base/logging.h" -#include "base/memory/ptr_util.h" -#include "components/safe_browsing/android/remote_database_manager.h" -#include "services/network/public/cpp/shared_url_loader_factory.h" -#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h" - -namespace safe_browsing { - -// static -std::unique_ptr<ServicesDelegate> ServicesDelegate::Create( - SafeBrowsingService* safe_browsing_service) { - return base::WrapUnique(new ServicesDelegateStub); -} - -// static -std::unique_ptr<ServicesDelegate> ServicesDelegate::CreateForTest( - SafeBrowsingService* safe_browsing_service, - ServicesDelegate::ServicesCreator* services_creator) { - NOTREACHED(); - return base::WrapUnique(new ServicesDelegateStub); -} - -ServicesDelegateStub::ServicesDelegateStub() {} - -ServicesDelegateStub::~ServicesDelegateStub() {} - -void ServicesDelegateStub::InitializeCsdService( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {} - -const scoped_refptr<SafeBrowsingDatabaseManager>& -ServicesDelegateStub::database_manager() const { - return database_manager_; -} - -void ServicesDelegateStub::Initialize() { - if (!database_manager_set_for_tests_) { - database_manager_ = - base::WrapRefCounted(new RemoteSafeBrowsingDatabaseManager()); - } -} -void ServicesDelegateStub::SetDatabaseManagerForTest( - SafeBrowsingDatabaseManager* database_manager) { - database_manager_set_for_tests_ = true; - database_manager_ = database_manager; -} - -void ServicesDelegateStub::ShutdownServices() {} - -void ServicesDelegateStub::RefreshState(bool enable) {} - -void ServicesDelegateStub::ProcessResourceRequest( - const ResourceRequestInfo* request) {} - -std::unique_ptr<prefs::mojom::TrackedPreferenceValidationDelegate> -ServicesDelegateStub::CreatePreferenceValidationDelegate(Profile* profile) { - return nullptr; -} - -void ServicesDelegateStub::RegisterDelayedAnalysisCallback( - const DelayedAnalysisCallback& callback) {} - -void ServicesDelegateStub::AddDownloadManager( - content::DownloadManager* download_manager) {} - -ClientSideDetectionService* ServicesDelegateStub::GetCsdService() { - return nullptr; -} - -DownloadProtectionService* ServicesDelegateStub::GetDownloadService() { - return nullptr; -} - -void ServicesDelegateStub::StartOnIOThread( - scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory, - const V4ProtocolConfig& v4_config) { - database_manager_->StartOnIOThread(url_loader_factory, v4_config); -} - -void ServicesDelegateStub::StopOnIOThread(bool shutdown) { - database_manager_->StopOnIOThread(shutdown); -} - -void ServicesDelegateStub::CreatePasswordProtectionService(Profile* profile) {} -void ServicesDelegateStub::RemovePasswordProtectionService(Profile* profile) {} -PasswordProtectionService* ServicesDelegateStub::GetPasswordProtectionService( - Profile* profile) const { - NOTIMPLEMENTED(); - return nullptr; -} - -} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc new file mode 100644 index 0000000..489c9ed9 --- /dev/null +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.cc
@@ -0,0 +1,136 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h" + +#include <algorithm> + +#include "base/metrics/histogram_macros.h" +#include "chrome/browser/history/history_service_factory.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/safe_browsing/safe_browsing_service.h" +#include "components/download/public/common/download_item.h" +#include "components/keyed_service/core/service_access_type.h" +#include "components/prefs/pref_service.h" +#include "components/safe_browsing/features.h" +#include "components/safe_browsing/triggers/trigger_manager.h" +#include "content/public/browser/download_item_utils.h" +#include "content/public/browser/download_manager.h" +#include "content/public/browser/render_process_host.h" +#include "content/public/browser/storage_partition.h" + +namespace safe_browsing { + +namespace { +// MIME-type for APKs. +const char kApkMimeType[] = "application/vnd.android.package-archive"; + +bool IsFeatureEnabled() { + return base::FeatureList::IsEnabled(safe_browsing::kTelemetryForApkDownloads); +} +} // namespace + +AndroidTelemetryService::AndroidTelemetryService( + SafeBrowsingService* sb_service, + Profile* profile) + : TelemetryService(), + profile_(profile), + sb_service_(sb_service), + trigger_manager_(sb_service->trigger_manager()) { + DCHECK(profile_); + DCHECK(IsSafeBrowsingEnabled()); + if (!IsFeatureEnabled()) { + return; + } + + content::DownloadManager* download_manager = + content::BrowserContext::GetDownloadManager(profile_); + if (download_manager) { + // Look for new downloads being created. + download_manager->AddObserver(this); + } +} + +AndroidTelemetryService::~AndroidTelemetryService() { + content::DownloadManager* download_manager = + content::BrowserContext::GetDownloadManager(profile_); + if (download_manager) { + download_manager->RemoveObserver(this); + } +} + +void AndroidTelemetryService::OnDownloadCreated( + content::DownloadManager* manager, + download::DownloadItem* item) { + DCHECK(IsFeatureEnabled()); + + content::WebContents* web_contents = + content::DownloadItemUtils::GetWebContents(item); + if (!web_contents) { + // TODO(vakh): This can happen sometimes on a browser launch. Identify this + // case and document it better. + return; + } + + if (item->GetMimeType() != kApkMimeType) { + return; + } + + item->AddObserver(this); + StartThreatDetailsCollection(web_contents); +} + +void AndroidTelemetryService::OnDownloadUpdated(download::DownloadItem* item) { + DCHECK(IsFeatureEnabled()); + DCHECK_EQ(kApkMimeType, item->GetMimeType()); + + if (item->GetState() == download::DownloadItem::COMPLETE) { + // Download completed. Send report, if allowed. + content::WebContents* web_contents = + content::DownloadItemUtils::GetWebContents(item); + FinishCollectingThreatDetails(web_contents); + } +} + +const PrefService* AndroidTelemetryService::GetPrefs() { + return profile_->GetPrefs(); +} + +bool AndroidTelemetryService::IsSafeBrowsingEnabled() { + return GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled); +} + +void AndroidTelemetryService::StartThreatDetailsCollection( + content::WebContents* web_contents) { + security_interstitials::UnsafeResource resource; + resource.threat_type = SB_THREAT_TYPE_APK_DOWNLOAD; + resource.url = web_contents->GetLastCommittedURL(); + resource.web_contents_getter = resource.GetWebContentsGetter( + web_contents->GetMainFrame()->GetProcess()->GetID(), + web_contents->GetMainFrame()->GetRoutingID()); + + TriggerManagerReason reason; + // Ignores the return of |StartCollectingThreatDetails()| here and + // let TriggerManager decide whether it should start data + // collection. + trigger_manager_->StartCollectingThreatDetailsWithReason( + safe_browsing::TriggerType::APK_DOWNLOAD, web_contents, resource, + sb_service_->GetURLLoaderFactory(), + HistoryServiceFactory::GetForProfile(profile_, + ServiceAccessType::EXPLICIT_ACCESS), + TriggerManager::GetSBErrorDisplayOptions(*GetPrefs(), web_contents), + &reason); + // TODO(vakh): Log |reason|. +} + +void AndroidTelemetryService::FinishCollectingThreatDetails( + content::WebContents* web_contents) { + trigger_manager_->FinishCollectingThreatDetails( + safe_browsing::TriggerType::APK_DOWNLOAD, web_contents, + base::TimeDelta::FromMilliseconds(0), /*did_proceed=*/false, + /*num_visit=*/0, + TriggerManager::GetSBErrorDisplayOptions(*GetPrefs(), web_contents)); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h new file mode 100644 index 0000000..1c2a33e --- /dev/null +++ b/chrome/browser/safe_browsing/telemetry/android/android_telemetry_service.h
@@ -0,0 +1,85 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_ANDROID_ANDROID_TELEMETRY_SERVICE_H_ +#define CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_ANDROID_ANDROID_TELEMETRY_SERVICE_H_ + +#include <vector> + +#include "chrome/browser/safe_browsing/telemetry/telemetry_service.h" +#include "components/download/public/common/download_item.h" +#include "components/safe_browsing/proto/csd.pb.h" +#include "content/public/browser/download_manager.h" + +class Profile; +class PrefService; + +namespace content { +class WebContents; +} + +namespace safe_browsing { + +class SafeBrowsingService; +class TriggerManager; + +// This class is used to send telemetry information to Safe Browsing for +// security related incidents. The information is sent only if: +// 1. The user has opted in to extended reporting, AND +// 2. The security incident did not happen in an incognito window. +// As the name suggests, this works only on Android. + +// The following events are currently considered security related incidents from +// the perspective of this class: +// 1. Downloading off-market APKs. See: go/zurkon-v1-referrer-dd + +class AndroidTelemetryService : public download::DownloadItem::Observer, + public content::DownloadManager::Observer, + public TelemetryService { + public: + AndroidTelemetryService(SafeBrowsingService* sb_service, Profile* profile); + ~AndroidTelemetryService() override; + + // content::DownloadManager::Observer. + // Called when a new download is created. + void OnDownloadCreated(content::DownloadManager* manager, + download::DownloadItem* item) override; + + // download::DownloadItem::Observer + // Called when the state of a download item changes. + void OnDownloadUpdated(download::DownloadItem* download) override; + + private: + // Calls into |trigger_manager_| to start collecting information about the + // download event. This information is then sent to Safe Browsing service + // in the form of a |ClientSafeBrowsingReportRequest| message. + // If the download gets cancelled, the report isn't sent. + void StartThreatDetailsCollection(content::WebContents* web_contents); + + // Calls into |trigger_manager_| to prepare to send the referrer chain and + // other information to Safe Browsing service. Only called when the download + // completes and only for users who have opted into extended reporting. + void FinishCollectingThreatDetails(content::WebContents* web_contents); + + // Helper method to get prefs from |profile_|. + const PrefService* GetPrefs(); + + // Helper method to check if Safe Browsing is enabled. + bool IsSafeBrowsingEnabled(); + + // Profile associated with this instance. Unowned. + Profile* profile_; + + // Unowned. + SafeBrowsingService* sb_service_; + + // Used to send the ClientSafeBrowsingReportRequest report. Unowned. + TriggerManager* trigger_manager_; + + DISALLOW_COPY_AND_ASSIGN(AndroidTelemetryService); +}; + +} // namespace safe_browsing + +#endif // CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_ANDROID_ANDROID_TELEMETRY_SERVICE_H_
diff --git a/chrome/browser/safe_browsing/telemetry/telemetry_service.cc b/chrome/browser/safe_browsing/telemetry/telemetry_service.cc new file mode 100644 index 0000000..73298e9 --- /dev/null +++ b/chrome/browser/safe_browsing/telemetry/telemetry_service.cc
@@ -0,0 +1,15 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/safe_browsing/telemetry/telemetry_service.h" + +namespace safe_browsing { + +TelemetryService::TelemetryService() : weak_factory_(this) {} + +TelemetryService::~TelemetryService() { + weak_factory_.InvalidateWeakPtrs(); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/telemetry/telemetry_service.h b/chrome/browser/safe_browsing/telemetry/telemetry_service.h new file mode 100644 index 0000000..da3b0750 --- /dev/null +++ b/chrome/browser/safe_browsing/telemetry/telemetry_service.h
@@ -0,0 +1,31 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_TELEMETRY_SERVICE_H_ +#define CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_TELEMETRY_SERVICE_H_ + +#include "base/memory/weak_ptr.h" + +namespace safe_browsing { + +// This class is used to send telemetry related to security incidents to Safe +// Browsing. It is currently only implemented for downoads of APK files on +// Android. See |AndroidTelemetryService|. +class TelemetryService { + public: + TelemetryService(); + virtual ~TelemetryService(); + + base::WeakPtr<TelemetryService> GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + + private: + base::WeakPtrFactory<TelemetryService> weak_factory_; + DISALLOW_COPY_AND_ASSIGN(TelemetryService); +}; + +} // namespace safe_browsing + +#endif // CHROME_BROWSER_SAFE_BROWSING_TELEMETRY_TELEMETRY_SERVICE_H_
diff --git a/chrome/browser/ssl/security_state_tab_helper.cc b/chrome/browser/ssl/security_state_tab_helper.cc index 9a59c907..254f203e 100644 --- a/chrome/browser/ssl/security_state_tab_helper.cc +++ b/chrome/browser/ssl/security_state_tab_helper.cc
@@ -251,6 +251,7 @@ case safe_browsing::SB_THREAT_TYPE_CSD_WHITELIST: case safe_browsing::SB_THREAT_TYPE_AD_SAMPLE: case safe_browsing::SB_THREAT_TYPE_SUSPICIOUS_SITE: + case safe_browsing::SB_THREAT_TYPE_APK_DOWNLOAD: // These threat types are not currently associated with // interstitials, and thus resources with these threat types are // not ever whitelisted or pending whitelisting.
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 80d3832..9e95256 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -691,10 +691,12 @@ // However, if the frame is already very dark or very light, respectively, // this won't contrast sufficiently with the frame color, so we'll need to // reverse when we're lightening and darkening. - const bool lighten = color_utils::GetRelativeLuminance(tab_color) < - color_utils::GetRelativeLuminance(frame_color); - SkColor separator_color = - lighten ? SK_ColorWHITE : color_utils::GetDarkestColor(); + SkColor separator_color = SK_ColorWHITE; + if (color_utils::GetRelativeLuminance(tab_color) >= + color_utils::GetRelativeLuminance(frame_color)) { + separator_color = + color_utils::BlendTowardOppositeLuma(separator_color, SK_AlphaOPAQUE); + } SkAlpha alpha = color_utils::FindBlendValueForContrastRatio( frame_color, separator_color, frame_color, kContrastRatio, 0);
diff --git a/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc b/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc index f5e2d77a..3ecac7c 100644 --- a/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc +++ b/chrome/browser/ui/ash/accessibility/accessibility_controller_client_unittest.cc
@@ -51,6 +51,7 @@ const std::vector<int>& keys_to_capture) override {} void ToggleDictationFromSource( ash::mojom::DictationToggleSource source) override {} + void ForwardKeyEventsToSwitchAccess(bool should_forward) override {} bool was_client_set() const { return was_client_set_; }
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc index a9f6a96..145334f 100644 --- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc +++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer.cc
@@ -290,13 +290,27 @@ domain_and_registry)) { return std::string(); } + const std::string domain_without_registry = + url_formatter::top_domains::HostnameWithoutRegistry(domain_and_registry); for (const std::string& skeleton : url_formatter::GetSkeletons(base::UTF8ToUTF16(domain_and_registry))) { for (const char* const top_domain_skeleton : kTop500) { if (IsEditDistanceAtMostOne(base::UTF8ToUTF16(skeleton), base::UTF8ToUTF16(top_domain_skeleton))) { - return url_formatter::LookupSkeletonInTopDomains(top_domain_skeleton); + const std::string top_domain = + url_formatter::LookupSkeletonInTopDomains(top_domain_skeleton); + DCHECK(!top_domain.empty()); + // If the only difference between the navigated and top + // domains is the registry part, this is unlikely to be a spoofing + // attempt. Ignore this match and continue. E.g. If the navigated domain + // is google.com.tw and the top domain is google.com.tr, this won't + // produce a match. + const std::string top_domain_without_registry = + url_formatter::top_domains::HostnameWithoutRegistry(top_domain); + if (domain_without_registry != top_domain_without_registry) { + return top_domain; + } } } }
diff --git a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc index 47e2e37..9b0aa96 100644 --- a/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc +++ b/chrome/browser/ui/omnibox/lookalike_url_navigation_observer_browsertest.cc
@@ -337,6 +337,20 @@ LookalikeUrlNavigationObserver::MatchType::kEditDistance); } +// Tests negative examples for the edit distance. +IN_PROC_BROWSER_TEST_P(LookalikeUrlNavigationObserverBrowserTest, + Idn_TopDomainEditDistance_NoMatch) { + // Matches google.com.tr but only differs in registry. + TestInfobarNotShown( + embedded_test_server()->GetURL("google.com.tw", "/title1.html")); + CheckNoUkm(); + + // Matches ask.com but is too short. + TestInfobarNotShown( + embedded_test_server()->GetURL("asq.com", "/title1.html")); + CheckNoUkm(); +} + // Navigate to a domain whose visual representation looks like a domain with a // site engagement score above a certain threshold. This should record metrics. // It should also show a "Did you mean to go to ..." infobar if configured via
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc index 665718d..63b88c0 100644 --- a/chrome/browser/ui/startup/startup_browser_creator.cc +++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -66,7 +66,6 @@ #include "content/public/browser/notification_source.h" #include "content/public/common/content_switches.h" #include "extensions/common/switches.h" -#include "net/base/port_util.h" #include "printing/buildflags/buildflags.h" #if defined(OS_CHROMEOS) @@ -588,12 +587,6 @@ } #endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) - if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) { - std::string allowed_ports = - command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); - net::SetExplicitlyAllowedPorts(allowed_ports); - } - if (command_line.HasSwitch(switches::kValidateCrx)) { if (!process_startup) { LOG(ERROR) << "chrome is already running; you must close all running "
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc index 9f404f1..d4bae96 100644 --- a/chrome/browser/ui/tab_helpers.cc +++ b/chrome/browser/ui/tab_helpers.cc
@@ -45,6 +45,7 @@ #include "chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/resource_coordinator/tab_helper.h" +#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h" #include "chrome/browser/safe_browsing/trigger_creator.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/ssl/connection_help_tab_helper.h" @@ -105,7 +106,6 @@ #else #include "chrome/browser/banners/app_banner_manager_desktop.h" #include "chrome/browser/plugins/plugin_observer.h" -#include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h" #include "chrome/browser/safe_browsing/safe_browsing_tab_observer.h" #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h" #include "chrome/browser/ui/hung_plugin_tab_helper.h" @@ -245,6 +245,8 @@ PreviewsUITabHelper::CreateForWebContents(web_contents); RecentlyAudibleHelper::CreateForWebContents(web_contents); ResourceLoadingHintsWebContentsObserver::CreateForWebContents(web_contents); + safe_browsing::SafeBrowsingNavigationObserver::MaybeCreateForWebContents( + web_contents); safe_browsing::TriggerCreator::MaybeCreateTriggersForWebContents( profile, web_contents); SearchEngineTabHelper::CreateForWebContents(web_contents); @@ -300,8 +302,6 @@ PluginObserver::CreateForWebContents(web_contents); SadTabHelper::CreateForWebContents(web_contents); safe_browsing::SafeBrowsingTabObserver::CreateForWebContents(web_contents); - safe_browsing::SafeBrowsingNavigationObserver::MaybeCreateForWebContents( - web_contents); SearchTabHelper::CreateForWebContents(web_contents); TabDialogs::CreateForWebContents(web_contents); web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h index e7dc251..8e17b69 100644 --- a/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/eula_screen_handler.h
@@ -10,7 +10,6 @@ #include "base/memory/ref_counted.h" #include "chrome/browser/chromeos/login/screens/eula_view.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" -#include "chromeos/tpm/tpm_password_fetcher.h" #include "components/login/secure_module_util_chromeos.h" #include "content/public/browser/web_ui.h" @@ -25,9 +24,7 @@ // WebUI implementation of EulaScreenView. It is used to interact // with the eula part of the JS page. -class EulaScreenHandler : public EulaView, - public BaseScreenHandler, - public TpmPasswordFetcherDelegate { +class EulaScreenHandler : public EulaView, public BaseScreenHandler { public: explicit EulaScreenHandler(CoreOobeView* core_oobe_view); ~EulaScreenHandler() override;
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc index 676de05..33395114 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.cc
@@ -26,7 +26,7 @@ #include "chromeos/dbus/debug_daemon_client.h" #include "chromeos/printing/ppd_provider.h" #include "chromeos/printing/printer_configuration.h" -#include "components/printing/common/printer_capabilities.h" +#include "components/printing/browser/printer_capabilities.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "printing/backend/print_backend_consts.h"
diff --git a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc index 8af704d9..dc23201 100644 --- a/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc +++ b/chrome/browser/ui/webui/print_preview/local_printer_handler_default.cc
@@ -13,13 +13,13 @@ #include "base/threading/scoped_blocking_call.h" #include "build/build_config.h" #include "chrome/browser/ui/webui/print_preview/print_preview_utils.h" -#include "components/printing/common/printer_capabilities.h" +#include "components/printing/browser/printer_capabilities.h" #include "content/public/browser/browser_thread.h" #include "printing/backend/print_backend.h" #if defined(OS_MACOSX) #include "components/printing/browser/features.h" -#include "components/printing/common/printer_capabilities_mac.h" +#include "components/printing/browser/printer_capabilities_mac.h" #endif namespace printing {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc index 87977229..42a6368f 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -60,9 +60,9 @@ #include "components/cloud_devices/common/cloud_devices_urls.h" #include "components/cloud_devices/common/printer_description.h" #include "components/prefs/pref_service.h" +#include "components/printing/browser/printer_capabilities.h" #include "components/printing/common/cloud_print_cdd_conversion.h" #include "components/printing/common/print_messages.h" -#include "components/printing/common/printer_capabilities.h" #include "components/signin/core/browser/account_consistency_method.h" #include "components/signin/core/browser/gaia_cookie_manager_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h"
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc index f3db3ad..48eca940 100644 --- a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc +++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
@@ -21,7 +21,7 @@ #include "chrome/browser/printing/print_view_manager.h" #include "chrome/browser/ui/webui/print_preview/printer_handler.h" #include "components/crash/core/common/crash_keys.h" -#include "components/printing/common/printer_capabilities.h" +#include "components/printing/browser/printer_capabilities.h" #include "content/public/browser/render_frame_host.h" #include "printing/backend/print_backend_consts.h" #include "printing/page_range.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc index f03b7f73..732ffb6d 100644 --- a/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc +++ b/chrome/browser/ui/webui/settings/chromeos/account_manager_handler.cc
@@ -147,7 +147,6 @@ if (!icon.IsEmpty()) { account.SetString("pic", webui::GetBitmapDataUrl(icon.AsBitmap())); } else { - // TODO(crbug.com/914751): Badge this icon with an exclamation mark. gfx::ImageSkia default_icon = *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( IDR_LOGIN_DEFAULT_USER);
diff --git a/chrome/common/extensions/api/accessibility_private.json b/chrome/common/extensions/api/accessibility_private.json index 14929d15..2e7c672 100644 --- a/chrome/common/extensions/api/accessibility_private.json +++ b/chrome/common/extensions/api/accessibility_private.json
@@ -222,6 +222,18 @@ "platforms": ["chromeos"] }, { + "name": "forwardKeyEventsToSwitchAccess", + "type": "function", + "description": "When enabled, forwards key events to the Switch Access extension", + "parameters": [ + { + "name": "shouldForward", + "type": "boolean" + } + ], + "platforms": ["chromeos"] + }, + { "name": "setNativeChromeVoxArcSupportForCurrentApp", "type": "function", "description": "Sets current ARC app to use native ARC support.",
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index e20a97e..26d0740 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -3406,7 +3406,6 @@ if (include_js_tests) { deps += [ "//chrome/test/data/webui:unit_tests_js" ] data += [ - "$root_out_dir/test_data/chrome/browser/resources/print_preview/", "$root_out_dir/test_data/chrome/renderer/resources/extensions/", "$root_out_dir/test_data/ui/webui/", ]
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 293a2b1..d55e2853 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -174,14 +174,11 @@ test_type = "unit" sources = [ "../../../browser/resources/md_downloads/search_service_unittest.gtestjs", - "../../../browser/resources/print_preview/print_preview_utils_unittest.gtestjs", "../../../renderer/resources/extensions/notifications_custom_bindings.gtestjs", "../unit/framework_unittest.gtestjs", ] extra_js_files = [ "../../../browser/resources/md_downloads/browser_proxy.js", - "../../../browser/resources/print_preview/data/measurement_system.js", - "../../../browser/resources/print_preview/print_preview_utils.js", "../../../browser/resources/md_downloads/search_service.js", "../../../renderer/resources/extensions/notifications_custom_bindings.js", "../../../renderer/resources/extensions/notifications_test_util.js",
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn index 20a2f232..c351215 100644 --- a/chromeos/BUILD.gn +++ b/chromeos/BUILD.gn
@@ -43,7 +43,6 @@ "//base/third_party/dynamic_annotations", "//chromeos/cryptohome", "//chromeos/dbus:authpolicy_proto", - "//chromeos/dbus:cryptohome_proto", "//chromeos/dbus:vm_applications_apps_proto", "//chromeos/login/auth", "//chromeos/login/login_state", @@ -148,12 +147,6 @@ "timezone/timezone_request.h", "timezone/timezone_resolver.cc", "timezone/timezone_resolver.h", - "tpm/tpm_password_fetcher.cc", - "tpm/tpm_password_fetcher.h", - "tpm/tpm_token_info_getter.cc", - "tpm/tpm_token_info_getter.h", - "tpm/tpm_token_loader.cc", - "tpm/tpm_token_loader.h", ] if (current_cpu == "arm" || current_cpu == "x86") { defines = [ "BINDER_IPC_32BIT" ] @@ -303,6 +296,7 @@ "//chromeos/network:unit_tests", "//chromeos/services:unit_tests", "//chromeos/settings:unit_tests", + "//chromeos/tpm:unit_tests", "//components/account_id", "//components/onc", "//components/policy:generated", @@ -350,7 +344,6 @@ "test/run_all_unittests.cc", "timezone/timezone_unittest.cc", "tools/variable_expander_unittest.cc", - "tpm/tpm_token_info_getter_unittest.cc", ] data = [
diff --git a/chromeos/test/data/oobe_configuration/TestSkipHIDDetection.json b/chromeos/test/data/oobe_configuration/TestSkipHIDDetection.json new file mode 100644 index 0000000..48292d43 --- /dev/null +++ b/chromeos/test/data/oobe_configuration/TestSkipHIDDetection.json
@@ -0,0 +1,4 @@ +{ + "skipHIDDetection": true, + "welcomeNext": true, +} \ No newline at end of file
diff --git a/chromeos/tpm/BUILD.gn b/chromeos/tpm/BUILD.gn new file mode 100644 index 0000000..272e250 --- /dev/null +++ b/chromeos/tpm/BUILD.gn
@@ -0,0 +1,44 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//testing/test.gni") + +assert(is_chromeos, "Non-Chrome-OS builds must not depend on //chromeos") + +component("tpm") { + defines = [ "IS_CHROMEOS_TPM_IMPL" ] + deps = [ + "//base", + "//chromeos/cryptohome", + "//chromeos/dbus", + "//chromeos/dbus:cryptohome_proto", + "//chromeos/login/login_state", + "//components/account_id", + "//crypto", + ] + sources = [ + "tpm_password_fetcher.cc", + "tpm_password_fetcher.h", + "tpm_token_info_getter.cc", + "tpm_token_info_getter.h", + "tpm_token_loader.cc", + "tpm_token_loader.h", + ] +} + +source_set("unit_tests") { + testonly = true + deps = [ + ":tpm", + "//base/test:test_support", + "//chromeos:chromeos_constants", + "//chromeos/cryptohome", + "//chromeos/dbus", + "//chromeos/dbus:cryptohome_proto", + "//testing/gtest", + ] + sources = [ + "tpm_token_info_getter_unittest.cc", + ] +}
diff --git a/chromeos/tpm/DEPS b/chromeos/tpm/DEPS new file mode 100644 index 0000000..c2bdbe1 --- /dev/null +++ b/chromeos/tpm/DEPS
@@ -0,0 +1,11 @@ +noparent = True + +include_rules = [ + "+base", + "+crypto", + "+chromeos/cryptohome", + "+chromeos/login/login_state", + "+chromeos/dbus", + "+components/account_id", + "+testing", +]
diff --git a/chromeos/tpm/tpm_password_fetcher.h b/chromeos/tpm/tpm_password_fetcher.h index b69d41b8..33db5d6 100644 --- a/chromeos/tpm/tpm_password_fetcher.h +++ b/chromeos/tpm/tpm_password_fetcher.h
@@ -7,23 +7,23 @@ #include <string> +#include "base/component_export.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" -#include "chromeos/chromeos_export.h" namespace chromeos { // Interface which TpmPasswordFetcher uses to notify that password has been // fetched. -class CHROMEOS_EXPORT TpmPasswordFetcherDelegate { +class COMPONENT_EXPORT(CHROMEOS_TPM) TpmPasswordFetcherDelegate { public: virtual ~TpmPasswordFetcherDelegate() {} virtual void OnPasswordFetched(const std::string& tpm_password) = 0; }; // Class for fetching TPM password from the Cryptohome. -class CHROMEOS_EXPORT TpmPasswordFetcher { +class COMPONENT_EXPORT(CHROMEOS_TPM) TpmPasswordFetcher { public: // Creates fetcher with the given delegate to be notified every time fetching // is done.
diff --git a/chromeos/tpm/tpm_token_info_getter.h b/chromeos/tpm/tpm_token_info_getter.h index b9b63f8..a7163de 100644 --- a/chromeos/tpm/tpm_token_info_getter.h +++ b/chromeos/tpm/tpm_token_info_getter.h
@@ -9,12 +9,12 @@ #include <string> #include "base/callback.h" +#include "base/component_export.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/optional.h" #include "base/time/time.h" -#include "chromeos/chromeos_export.h" #include "chromeos/dbus/cryptohome_client.h" #include "components/account_id/account_id.h" @@ -26,7 +26,7 @@ // Class for getting a user or the system TPM token info from cryptohome during // TPM token loading. -class CHROMEOS_EXPORT TPMTokenInfoGetter { +class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenInfoGetter { public: using TpmTokenInfoCallback = base::OnceCallback<void( base::Optional<CryptohomeClient::TpmTokenInfo> token_info)>;
diff --git a/chromeos/tpm/tpm_token_loader.h b/chromeos/tpm/tpm_token_loader.h index 146010a..9bde6965 100644 --- a/chromeos/tpm/tpm_token_loader.h +++ b/chromeos/tpm/tpm_token_loader.h
@@ -10,13 +10,13 @@ #include <vector> #include "base/callback_forward.h" +#include "base/component_export.h" #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/optional.h" #include "base/threading/thread_checker.h" -#include "chromeos/chromeos_export.h" #include "chromeos/dbus/cryptohome_client.h" #include "chromeos/login/login_state/login_state.h" #include "chromeos/tpm/tpm_token_info_getter.h" @@ -34,7 +34,8 @@ // session, the observers are notified using |OnTPMTokenReady|. // Note: This currently initializes the token with the hard coded default id 0. // See CryptohomeClient::OnPkcs11GetTpmTokenInfo. -class CHROMEOS_EXPORT TPMTokenLoader : public LoginState::Observer { +class COMPONENT_EXPORT(CHROMEOS_TPM) TPMTokenLoader + : public LoginState::Observer { public: enum TPMTokenStatus { TPM_TOKEN_STATUS_UNDETERMINED,
diff --git a/components/BUILD.gn b/components/BUILD.gn index 262a736..0ca8e4d 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -168,6 +168,7 @@ "//components/update_client:unit_tests", "//components/upload_list:unit_tests", "//components/url_formatter:unit_tests", + "//components/url_formatter/top_domains:unit_tests", "//components/url_matcher:unit_tests", "//components/url_pattern_index:unit_tests", "//components/variations:unit_tests", @@ -185,7 +186,7 @@ } if (use_viz_devtools) { - deps += [ "//components/ui_devtools/viz_views:unit_tests" ] + deps += [ "//components/ui_devtools/viz:unit_tests" ] } if (enable_nacl) { @@ -243,7 +244,6 @@ "//components/policy/core/browser:unit_tests", "//components/policy/core/common:unit_tests", "//components/previews/content:unit_tests", - "//components/printing/common:unit_tests", "//components/safe_browsing/common:unit_tests", "//components/safe_browsing/password_protection:password_protection_unittest", "//components/safe_browsing/triggers:unit_tests", @@ -354,7 +354,10 @@ } if (enable_basic_printing) { - deps += [ "//components/services/pdf_compositor:unit_tests" ] + deps += [ + "//components/printing/browser:unit_tests", + "//components/services/pdf_compositor:unit_tests", + ] } if (enable_print_preview) { deps += [ "//components/pwg_encoder:unit_tests" ]
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java index 95b34c0..d1ca29e 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUma.java
@@ -35,8 +35,9 @@ static final int BACKGROUND_TASK_COMPONENT_UPDATE = 15; static final int BACKGROUND_TASK_DEPRECATED_EXPLORE_SITES_REFRESH = 16; static final int BACKGROUND_TASK_EXPLORE_SITES_REFRESH = 17; + static final int BACKGROUND_TASK_DOWNLOAD_AUTO_RESUMPTION = 18; // Keep this one at the end and increment appropriately when adding new tasks. - static final int BACKGROUND_TASK_COUNT = 18; + static final int BACKGROUND_TASK_COUNT = 19; static final String KEY_CACHED_UMA = "bts_cached_uma"; @@ -243,6 +244,8 @@ return BACKGROUND_TASK_DOWNLOAD_SERVICE; case TaskIds.DOWNLOAD_CLEANUP_JOB_ID: return BACKGROUND_TASK_DOWNLOAD_CLEANUP; + case TaskIds.DOWNLOAD_AUTO_RESUMPTION_JOB_ID: + return BACKGROUND_TASK_DOWNLOAD_AUTO_RESUMPTION; case TaskIds.WEBVIEW_VARIATIONS_SEED_FETCH_JOB_ID: return BACKGROUND_TASK_WEBVIEW_VARIATIONS; case TaskIds.OFFLINE_PAGES_PREFETCH_NOTIFICATION_JOB_ID:
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java index a885f1c..959377ad 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java
@@ -26,6 +26,7 @@ public static final int WEBVIEW_VARIATIONS_SEED_FETCH_JOB_ID = 83; public static final int WEBAPK_UPDATE_JOB_ID = 91; public static final int DOWNLOAD_RESUMPTION_JOB_ID = 55; + public static final int DOWNLOAD_AUTO_RESUMPTION_JOB_ID = 56; public static final int FEED_REFRESH_JOB_ID = 22; public static final int COMPONENT_UPDATE_JOB_ID = 2; public static final int DEPRECATED_EXPLORE_SITES_REFRESH_JOB_ID = 100;
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java index 8a9dc167..905c63d 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerUmaTest.java
@@ -71,6 +71,9 @@ assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_DOWNLOAD_CLEANUP, BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( TaskIds.DOWNLOAD_CLEANUP_JOB_ID)); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_DOWNLOAD_AUTO_RESUMPTION, + BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( + TaskIds.DOWNLOAD_AUTO_RESUMPTION_JOB_ID)); assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_WEBVIEW_VARIATIONS, BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( TaskIds.WEBVIEW_VARIATIONS_SEED_FETCH_JOB_ID)); @@ -93,7 +96,7 @@ assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_DEPRECATED_EXPLORE_SITES_REFRESH, BackgroundTaskSchedulerUma.toUmaEnumValueFromTaskId( TaskIds.DEPRECATED_EXPLORE_SITES_REFRESH_JOB_ID)); - assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 18); + assertEquals(BackgroundTaskSchedulerUma.BACKGROUND_TASK_COUNT, 19); } @Test
diff --git a/components/certificate_transparency/data/log_list.json b/components/certificate_transparency/data/log_list.json index 6554ebef..a82a68f 100644 --- a/components/certificate_transparency/data/log_list.json +++ b/components/certificate_transparency/data/log_list.json
@@ -207,6 +207,56 @@ "dns_api_endpoint": "digicert-yeti2022.ct.googleapis.com" }, { + "description": "DigiCert Nessie2018 Log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVqpLa2W+Rz1XDZPBIyKJO+KKFOYZTj9MpJWnZeFUqzc5aivOiWEVhs8Gy2AlH3irWPFjIZPZMs3Dv7M+0LbPyQ==", + "url": "nessie2018.ct.digicert.com/log/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "digicert-nessie2018.ct.googleapis.com" + }, + { + "description": "DigiCert Nessie2019 Log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEX+0nudCKImd7QCtelhMrDW0OXni5RE10tiiClZesmrwUk2iHLCoTHHVV+yg5D4n/rxCRVyRhikPpVDOLMLxJaA==", + "url": "nessie2019.ct.digicert.com/log/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "digicert-nessie2019.ct.googleapis.com" + }, + { + "description": "DigiCert Nessie2020 Log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4hHIyMVIrR9oShgbQMYEk8WX1lmkfFKB448Gn93KbsZnnwljDHY6MQqEnWfKGgMOq0gh3QK48c5ZB3UKSIFZ4g==", + "url": "nessie2020.ct.digicert.com/log/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "digicert-nessie2020.ct.googleapis.com" + }, + { + "description": "DigiCert Nessie2021 Log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9o7AiwrbGBIX6Lnc47I6OfLMdZnRzKoP5u072nBi6vpIOEooktTi1gNwlRPzGC2ySGfuc1xLDeaA/wSFGgpYFg==", + "url": "nessie2021.ct.digicert.com/log/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "digicert-nessie2021.ct.googleapis.com" + }, + { + "description": "DigiCert Nessie2022 Log", + "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJyTdaAMoy/5jvg4RR019F2ihEV1McclBKMe2okuX7MCv/C87v+nxsfz1Af+p+0lADGMkmNd5LqZVqxbGvlHYcQ==", + "url": "nessie2022.ct.digicert.com/log/", + "maximum_merge_delay": 86400, + "operated_by": [ + 2 + ], + "dns_api_endpoint": "digicert-nessie2022.ct.googleapis.com" + }, + { "description": "Symantec log", "key": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEluqsHEYMG1XcDfy1lCdGV0JwOmkY4r87xNuroPS2bMBTP01CEDPwWJePa75y9CrsHEKqAy8afig1dpkIPSEUhg==", "url": "ct.ws.symantec.com/", @@ -375,4 +425,4 @@ "id": 9 } ] -} +} \ No newline at end of file
diff --git a/components/download/internal/background_service/controller_impl.cc b/components/download/internal/background_service/controller_impl.cc index 717d390..eae2dc6 100644 --- a/components/download/internal/background_service/controller_impl.cc +++ b/components/download/internal/background_service/controller_impl.cc
@@ -401,6 +401,8 @@ case DownloadTaskType::CLEANUP_TASK: ScheduleCleanupTask(); break; + case DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK: + NOTREACHED(); } }
diff --git a/components/download/internal/background_service/stats.cc b/components/download/internal/background_service/stats.cc index ef8cf015..88aebf4a 100644 --- a/components/download/internal/background_service/stats.cc +++ b/components/download/internal/background_service/stats.cc
@@ -48,6 +48,8 @@ return "DownloadTask"; case DownloadTaskType::CLEANUP_TASK: return "CleanUpTask"; + case DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK: + return "DownloadAutoResumptionTask"; } NOTREACHED(); return std::string();
diff --git a/components/download/internal/common/download_item_impl.cc b/components/download/internal/common/download_item_impl.cc index a39e308..4b536f5 100644 --- a/components/download/internal/common/download_item_impl.cc +++ b/components/download/internal/common/download_item_impl.cc
@@ -588,10 +588,12 @@ } void DownloadItemImpl::UpdateResumptionInfo(bool user_resume) { - if (user_resume) + if (user_resume) { allow_metered_ |= delegate_->IsActiveNetworkMetered(); + bytes_wasted_ = 0; + } - auto_resume_count_ = user_resume ? 0 : auto_resume_count_++; + auto_resume_count_ = user_resume ? 0 : ++auto_resume_count_; } void DownloadItemImpl::Cancel(bool user_cancel) {
diff --git a/components/download/internal/common/download_item_impl_delegate.cc b/components/download/internal/common/download_item_impl_delegate.cc index 973248a..cc3fb6af5d 100644 --- a/components/download/internal/common/download_item_impl_delegate.cc +++ b/components/download/internal/common/download_item_impl_delegate.cc
@@ -5,7 +5,9 @@ #include "components/download/public/common/download_item_impl_delegate.h" #include "base/logging.h" +#include "build/build_config.h" #include "components/download/database/in_progress/download_entry.h" +#include "components/download/public/common/auto_resumption_handler.h" #include "components/download/public/common/download_danger_type.h" #include "components/download/public/common/download_item_impl.h" @@ -94,7 +96,9 @@ } bool DownloadItemImplDelegate::IsActiveNetworkMetered() const { - return false; + return download::AutoResumptionHandler::Get() + ? download::AutoResumptionHandler::Get()->IsActiveNetworkMetered() + : false; } void DownloadItemImplDelegate::ReportBytesWasted(DownloadItemImpl* download) {}
diff --git a/components/download/internal/common/in_progress_download_manager.cc b/components/download/internal/common/in_progress_download_manager.cc index 276d856..abecb58 100644 --- a/components/download/internal/common/in_progress_download_manager.cc +++ b/components/download/internal/common/in_progress_download_manager.cc
@@ -409,6 +409,12 @@ on_initialized_callbacks_.clear(); } +void InProgressDownloadManager::GetAllDownloads( + std::vector<download::DownloadItem*>* downloads) const { + for (auto& item : in_progress_downloads_) + downloads->push_back(item.get()); +} + DownloadItemImpl* InProgressDownloadManager::GetInProgressDownload( const std::string& guid) { for (auto& item : in_progress_downloads_) {
diff --git a/components/download/public/background_service/download_task_types.h b/components/download/public/background_service/download_task_types.h index 48fcfb35..5140f520 100644 --- a/components/download/public/background_service/download_task_types.h +++ b/components/download/public/background_service/download_task_types.h
@@ -15,6 +15,9 @@ // Task to remove unnecessary files from the system. CLEANUP_TASK = 1, + + // Task to invoke the download auto-resumption handler. + DOWNLOAD_AUTO_RESUMPTION_TASK = 2, }; } // namespace download
diff --git a/components/download/public/common/BUILD.gn b/components/download/public/common/BUILD.gn index 8de5574..e14fe35 100644 --- a/components/download/public/common/BUILD.gn +++ b/components/download/public/common/BUILD.gn
@@ -15,6 +15,8 @@ component("public") { sources = [ + "auto_resumption_handler.cc", + "auto_resumption_handler.h", "base_file.h", "download_content.h", "download_create_info.h", @@ -65,6 +67,9 @@ public_deps = [ ":interfaces", + "//components/download/network", + "//components/download/public/background_service:public", + "//services/network/public/cpp", ] deps = [
diff --git a/components/download/public/common/auto_resumption_handler.cc b/components/download/public/common/auto_resumption_handler.cc new file mode 100644 index 0000000..3e6dfa5 --- /dev/null +++ b/components/download/public/common/auto_resumption_handler.cc
@@ -0,0 +1,295 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/public/common/auto_resumption_handler.h" + +#include <vector> + +#include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" +#include "base/strings/string_number_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/download/public/background_service/task_scheduler.h" +#include "url/gurl.h" + +namespace { + +static download::AutoResumptionHandler* g_auto_resumption_handler = nullptr; + +// The delay to wait for after a chrome restart before resuming all pending +// downloads so that tab loading doesn't get impacted. +const base::TimeDelta kAutoResumeStartupDelay = + base::TimeDelta::FromSeconds(10); + +// The interval at which various download updates are grouped together for +// computing the params for the task scheduler. +const base::TimeDelta kBatchDownloadUpdatesInterval = + base::TimeDelta::FromSeconds(1); + +// The delay to wait for before immediately retrying a download after it got +// interrupted due to network reasons. +const base::TimeDelta kDownloadImmediateRetryDelay = + base::TimeDelta::FromSeconds(1); + +// The task type to use for scheduling a task. +const download::DownloadTaskType kResumptionTaskType = + download::DownloadTaskType::DOWNLOAD_AUTO_RESUMPTION_TASK; + +// The window start time after which the system should fire the task. +const int64_t kWindowStartTimeSeconds = 0; + +// The window end time before which the system should fire the task. +const int64_t kWindowEndTimeSeconds = 24 * 60 * 60; + +bool IsMetered(network::mojom::ConnectionType type) { + switch (type) { + case network::mojom::ConnectionType::CONNECTION_2G: + case network::mojom::ConnectionType::CONNECTION_3G: + case network::mojom::ConnectionType::CONNECTION_4G: + return true; + case network::mojom::ConnectionType::CONNECTION_ETHERNET: + case network::mojom::ConnectionType::CONNECTION_WIFI: + case network::mojom::ConnectionType::CONNECTION_UNKNOWN: + case network::mojom::ConnectionType::CONNECTION_NONE: + case network::mojom::ConnectionType::CONNECTION_BLUETOOTH: + return false; + } + NOTREACHED(); + return false; +} + +bool IsConnected(network::mojom::ConnectionType type) { + switch (type) { + case network::mojom::ConnectionType::CONNECTION_UNKNOWN: + case network::mojom::ConnectionType::CONNECTION_NONE: + case network::mojom::ConnectionType::CONNECTION_BLUETOOTH: + return false; + default: + return true; + } +} + +bool IsInterruptedDownloadAutoResumable(download::DownloadItem* download_item, + int auto_resumption_size_limit) { + if (!download_item->GetURL().SchemeIsHTTPOrHTTPS()) + return false; + + if (download_item->GetBytesWasted() > auto_resumption_size_limit) + return false; + + int interrupt_reason = download_item->GetLastReason(); + DCHECK_NE(interrupt_reason, download::DOWNLOAD_INTERRUPT_REASON_NONE); + return interrupt_reason == + download::DOWNLOAD_INTERRUPT_REASON_NETWORK_TIMEOUT || + interrupt_reason == + download::DOWNLOAD_INTERRUPT_REASON_NETWORK_FAILED || + interrupt_reason == + download::DOWNLOAD_INTERRUPT_REASON_NETWORK_DISCONNECTED || + interrupt_reason == download::DOWNLOAD_INTERRUPT_REASON_CRASH; +} + +} // namespace + +namespace download { + +AutoResumptionHandler::Config::Config() : auto_resumption_size_limit(0) {} + +// static +void AutoResumptionHandler::Create( + std::unique_ptr<download::NetworkStatusListener> network_listener, + std::unique_ptr<download::TaskManager> task_manager, + std::unique_ptr<Config> config) { + DCHECK(!g_auto_resumption_handler); + g_auto_resumption_handler = new AutoResumptionHandler( + std::move(network_listener), std::move(task_manager), std::move(config)); +} + +// static +AutoResumptionHandler* AutoResumptionHandler::Get() { + return g_auto_resumption_handler; +} + +AutoResumptionHandler::AutoResumptionHandler( + std::unique_ptr<download::NetworkStatusListener> network_listener, + std::unique_ptr<download::TaskManager> task_manager, + std::unique_ptr<Config> config) + : network_listener_(std::move(network_listener)), + task_manager_(std::move(task_manager)), + config_(std::move(config)), + weak_factory_(this) { + network_listener_->Start(this); +} + +AutoResumptionHandler::~AutoResumptionHandler() { + network_listener_->Stop(); +} + +void AutoResumptionHandler::SetResumableDownloads( + const std::vector<download::DownloadItem*>& downloads) { + resumable_downloads_.clear(); + for (auto* download : downloads) { + if (!IsAutoResumableDownload(download)) + continue; + resumable_downloads_.insert(std::make_pair(download->GetGuid(), download)); + download->RemoveObserver(this); + download->AddObserver(this); + } + + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&AutoResumptionHandler::ResumePendingDownloads, + weak_factory_.GetWeakPtr()), + kAutoResumeStartupDelay); +} + +bool AutoResumptionHandler::IsActiveNetworkMetered() const { + return IsMetered(network_listener_->GetConnectionType()); +} + +void AutoResumptionHandler::OnNetworkChanged( + network::mojom::ConnectionType type) { + if (!IsConnected(type)) + return; + + ResumePendingDownloads(); +} + +void AutoResumptionHandler::OnDownloadStarted(download::DownloadItem* item) { + item->RemoveObserver(this); + item->AddObserver(this); + + OnDownloadUpdated(item); +} + +void AutoResumptionHandler::OnDownloadUpdated(download::DownloadItem* item) { + if (IsAutoResumableDownload(item)) + resumable_downloads_[item->GetGuid()] = item; + else + resumable_downloads_.erase(item->GetGuid()); + + if (item->GetState() == download::DownloadItem::INTERRUPTED && + IsAutoResumableDownload(item) && SatisfiesNetworkRequirements(item)) { + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&AutoResumptionHandler::ResumeDownload, + weak_factory_.GetWeakPtr(), item), + kDownloadImmediateRetryDelay); + return; + } + RecomputeTaskParams(); +} + +void AutoResumptionHandler::OnDownloadRemoved(download::DownloadItem* item) { + resumable_downloads_.erase(item->GetGuid()); + RecomputeTaskParams(); +} + +void AutoResumptionHandler::ResumeDownload(download::DownloadItem* download) { + if (SatisfiesNetworkRequirements(download)) + download->Resume(false); + else + RecomputeTaskParams(); +} + +void AutoResumptionHandler::OnStartScheduledTask( + download::TaskFinishedCallback callback) { + task_manager_->OnStartScheduledTask(kResumptionTaskType, std::move(callback)); + ResumePendingDownloads(); +} + +bool AutoResumptionHandler::OnStopScheduledTask() { + task_manager_->OnStopScheduledTask(kResumptionTaskType); + RescheduleTaskIfNecessary(); + return false; +} + +void AutoResumptionHandler::RecomputeTaskParams() { + if (recompute_task_params_scheduled_) + return; + + recompute_task_params_scheduled_ = true; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&AutoResumptionHandler::RescheduleTaskIfNecessary, + weak_factory_.GetWeakPtr()), + kBatchDownloadUpdatesInterval); +} + +void AutoResumptionHandler::RescheduleTaskIfNecessary() { + recompute_task_params_scheduled_ = false; + + bool has_resumable_downloads = false; + bool has_actionable_downloads = false; + bool can_download_on_metered = false; + for (auto iter = resumable_downloads_.begin(); + iter != resumable_downloads_.end(); ++iter) { + download::DownloadItem* download = iter->second; + if (!IsAutoResumableDownload(download)) + continue; + + has_resumable_downloads = true; + has_actionable_downloads |= SatisfiesNetworkRequirements(download); + can_download_on_metered |= download->AllowMetered(); + if (can_download_on_metered) + break; + } + + if (!has_actionable_downloads) + task_manager_->NotifyTaskFinished(kResumptionTaskType, false); + + if (!has_resumable_downloads) { + task_manager_->UnscheduleTask(kResumptionTaskType); + return; + } + + download::TaskManager::TaskParams task_params; + task_params.require_unmetered_network = !can_download_on_metered; + task_params.window_start_time_seconds = kWindowStartTimeSeconds; + task_params.window_end_time_seconds = kWindowEndTimeSeconds; + task_manager_->ScheduleTask(kResumptionTaskType, task_params); +} + +void AutoResumptionHandler::ResumePendingDownloads() { + for (auto iter = resumable_downloads_.begin(); + iter != resumable_downloads_.end(); ++iter) { + download::DownloadItem* download = iter->second; + if (!IsAutoResumableDownload(download)) + continue; + + if (SatisfiesNetworkRequirements(download)) + download->Resume(false); + } +} + +bool AutoResumptionHandler::SatisfiesNetworkRequirements( + download::DownloadItem* download) { + if (!IsConnected(network_listener_->GetConnectionType())) + return false; + + return download->AllowMetered() || !IsActiveNetworkMetered(); +} + +bool AutoResumptionHandler::IsAutoResumableDownload( + download::DownloadItem* item) { + if (item->IsDangerous()) + return false; + + switch (item->GetState()) { + case download::DownloadItem::IN_PROGRESS: + return !item->IsPaused(); + case download::DownloadItem::COMPLETE: + case download::DownloadItem::CANCELLED: + return false; + case download::DownloadItem::INTERRUPTED: + return !item->IsPaused() && + IsInterruptedDownloadAutoResumable( + item, config_->auto_resumption_size_limit); + case download::DownloadItem::MAX_DOWNLOAD_STATE: + NOTREACHED(); + } + + return false; +} + +} // namespace download
diff --git a/components/download/public/common/auto_resumption_handler.h b/components/download/public/common/auto_resumption_handler.h new file mode 100644 index 0000000..c0bb504 --- /dev/null +++ b/components/download/public/common/auto_resumption_handler.h
@@ -0,0 +1,90 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_PUBLIC_COMMON_AUTO_RESUMPTION_HANDLER_H_ +#define COMPONENTS_DOWNLOAD_PUBLIC_COMMON_AUTO_RESUMPTION_HANDLER_H_ + +#include <stddef.h> + +#include <memory> +#include <vector> + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/download/network/network_status_listener.h" +#include "components/download/public/background_service/task_manager.h" +#include "components/download/public/common/download_export.h" +#include "components/download/public/common/download_item.h" + +namespace download { + +// Handles auto-resumptions for downloads. Listens to network changes and +// schecules task to resume downloads accordingly. +class COMPONENTS_DOWNLOAD_EXPORT AutoResumptionHandler + : public download::NetworkStatusListener::Observer, + public download::DownloadItem::Observer { + public: + struct COMPONENTS_DOWNLOAD_EXPORT Config { + Config(); + ~Config() = default; + + int auto_resumption_size_limit; + }; + + // Creates the singleton instance of AutoResumptionHandler. + static void Create( + std::unique_ptr<download::NetworkStatusListener> network_listener, + std::unique_ptr<download::TaskManager> task_manager, + std::unique_ptr<Config> config); + + // Returns the singleton instance of the AutoResumptionHandler. + static AutoResumptionHandler* Get(); + + AutoResumptionHandler( + std::unique_ptr<download::NetworkStatusListener> network_listener, + std::unique_ptr<download::TaskManager> task_manager, + std::unique_ptr<Config> config); + ~AutoResumptionHandler() override; + + void SetResumableDownloads( + const std::vector<download::DownloadItem*>& downloads); + bool IsActiveNetworkMetered() const; + void OnStartScheduledTask(download::TaskFinishedCallback callback); + bool OnStopScheduledTask(); + + void OnDownloadStarted(download::DownloadItem* item); + + // DownloadItem::Observer overrides. + void OnDownloadUpdated(download::DownloadItem* item) override; + void OnDownloadRemoved(download::DownloadItem* item) override; + + private: + // NetworkStatusListener::Observer implementation. + void OnNetworkChanged(network::mojom::ConnectionType type) override; + + void ResumePendingDownloads(); + void RecomputeTaskParams(); + void RescheduleTaskIfNecessary(); + void ResumeDownload(download::DownloadItem* download); + bool SatisfiesNetworkRequirements(download::DownloadItem* download); + bool IsAutoResumableDownload(download::DownloadItem* item); + + std::unique_ptr<download::NetworkStatusListener> network_listener_; + + std::unique_ptr<download::TaskManager> task_manager_; + + std::unique_ptr<Config> config_; + + std::map<std::string, download::DownloadItem*> resumable_downloads_; + + bool recompute_task_params_scheduled_ = false; + + base::WeakPtrFactory<AutoResumptionHandler> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(AutoResumptionHandler); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_AUTO_RESUMPTION_HANDLER_H_
diff --git a/components/download/public/common/in_progress_download_manager.h b/components/download/public/common/in_progress_download_manager.h index d76534f..563d97d 100644 --- a/components/download/public/common/in_progress_download_manager.h +++ b/components/download/public/common/in_progress_download_manager.h
@@ -122,6 +122,9 @@ // Called to remove an in-progress download. void RemoveInProgressDownload(const std::string& guid); + // Called to get all in-progress downloads. + void GetAllDownloads(std::vector<download::DownloadItem*>* downloads) const; + // Called to retrieve an in-progress download. DownloadItemImpl* GetInProgressDownload(const std::string& guid);
diff --git a/components/gwp_asan/BUILD.gn b/components/gwp_asan/BUILD.gn index 8829da76..b4b82621 100644 --- a/components/gwp_asan/BUILD.gn +++ b/components/gwp_asan/BUILD.gn
@@ -4,11 +4,13 @@ source_set("unit_tests") { testonly = true + deps = [ + "//components/gwp_asan/common:unit_tests", + ] + if (is_win || is_mac) { + deps += [ "//components/gwp_asan/client:unit_tests" ] + } if (is_win) { - deps = [ - "//components/gwp_asan/client:unit_tests", - "//components/gwp_asan/common:unit_tests", - "//components/gwp_asan/crash_handler:unit_tests", - ] + deps += [ "//components/gwp_asan/crash_handler:unit_tests" ] } }
diff --git a/components/gwp_asan/client/BUILD.gn b/components/gwp_asan/client/BUILD.gn index 4018061..071d995 100644 --- a/components/gwp_asan/client/BUILD.gn +++ b/components/gwp_asan/client/BUILD.gn
@@ -2,8 +2,6 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -assert(is_win, "GWP-ASan client currently only supports Windows.") - component("client") { output_name = "gwp_asan_client" sources = [ @@ -20,6 +18,13 @@ "sampling_allocator_shims_win.h", ] + if (is_posix) { + sources += [ + "guarded_page_allocator_posix.cc", + "sampling_allocator_shims_posix.h", + ] + } + defines = [ "GWP_ASAN_IMPLEMENTATION" ] deps = [
diff --git a/components/gwp_asan/client/guarded_page_allocator_posix.cc b/components/gwp_asan/client/guarded_page_allocator_posix.cc new file mode 100644 index 0000000..d3e83f1 --- /dev/null +++ b/components/gwp_asan/client/guarded_page_allocator_posix.cc
@@ -0,0 +1,38 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/gwp_asan/client/guarded_page_allocator.h" + +#include <sys/mman.h> + +#include "base/logging.h" + +namespace gwp_asan { +namespace internal { + +void* GuardedPageAllocator::MapRegion() { + return mmap(nullptr, RegionSize(), PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, + 0); +} + +void GuardedPageAllocator::UnmapRegion() { + CHECK(state_.pages_base_addr); + int err = + munmap(reinterpret_cast<void*>(state_.pages_base_addr), RegionSize()); + DCHECK_EQ(err, 0); + (void)err; +} + +void GuardedPageAllocator::MarkPageReadWrite(void* ptr) { + int err = mprotect(ptr, state_.page_size, PROT_READ | PROT_WRITE); + PCHECK(err == 0) << "mprotect"; +} + +void GuardedPageAllocator::MarkPageInaccessible(void* ptr) { + int err = mprotect(ptr, state_.page_size, PROT_NONE); + PCHECK(err == 0) << "mprotect"; +} + +} // namespace internal +} // namespace gwp_asan
diff --git a/components/gwp_asan/client/sampling_allocator_shims.cc b/components/gwp_asan/client/sampling_allocator_shims.cc index be51e4d9..cc291ad 100644 --- a/components/gwp_asan/client/sampling_allocator_shims.cc +++ b/components/gwp_asan/client/sampling_allocator_shims.cc
@@ -20,6 +20,10 @@ #include "components/gwp_asan/client/export.h" #include "components/gwp_asan/client/guarded_page_allocator.h" +#if defined(OS_POSIX) +#include "components/gwp_asan/client/sampling_allocator_shims_posix.h" +#endif + #if defined(OS_WIN) #include "components/gwp_asan/client/sampling_allocator_shims_win.h" #endif @@ -172,9 +176,8 @@ void** results, unsigned num_requested, void* context) { -#if defined(OS_MACOSX) || defined(OS_IOS) -#error "Implement batch_malloc() support." -#endif + // The batch_malloc() routine is esoteric and only accessible for the system + // allocator's zone, GWP-ASan interception is not provided. return self->next->batch_malloc_function(self->next, size, results, num_requested, context); @@ -184,9 +187,18 @@ void** to_be_freed, unsigned num_to_be_freed, void* context) { -#if defined(OS_MACOSX) || defined(OS_IOS) -#error "Implement batch_free() support." -#endif + // A batch_free() hook is implemented because it is imperative that we never + // call free() with a GWP-ASan allocation. + for (size_t i = 0; i < num_to_be_freed; i++) { + if (UNLIKELY(gpa->PointerIsMine(to_be_freed[i]))) { + // If this batch includes guarded allocations, call free() on all of the + // individual allocations to ensure the guarded allocations are handled + // correctly. + for (size_t j = 0; j < num_to_be_freed; j++) + FreeFn(self, to_be_freed[j], context); + return; + } + } self->next->batch_free_function(self->next, to_be_freed, num_to_be_freed, context);
diff --git a/components/gwp_asan/client/sampling_allocator_shims_posix.h b/components/gwp_asan/client/sampling_allocator_shims_posix.h new file mode 100644 index 0000000..b85833e89 --- /dev/null +++ b/components/gwp_asan/client/sampling_allocator_shims_posix.h
@@ -0,0 +1,40 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_GWP_ASAN_CLIENT_SAMPLING_ALLOCATOR_SHIMS_POSIX_H_ +#define COMPONENTS_GWP_ASAN_CLIENT_SAMPLING_ALLOCATOR_SHIMS_POSIX_H_ + +#include <pthread.h> +#include <stddef.h> + +#include "base/logging.h" + +namespace gwp_asan { +namespace internal { + +// Due to https://crbug.com/881352 the sampling allocator shims can not use +// base::ThreadLocalStorage to access the TLS. Instead, we use platform-specific +// TLS APIs. +// +// TODO(vtsyrklevich): This implementation is identical to code in the +// base::PoissonAllocationSampler, see if they can share code. +using TLSKey = pthread_key_t; + +void TLSInit(TLSKey* key) { + int result = pthread_key_create(key, nullptr); + CHECK_EQ(0, result); +} + +size_t TLSGetValue(const TLSKey& key) { + return reinterpret_cast<size_t>(pthread_getspecific(key)); +} + +void TLSSetValue(const TLSKey& key, size_t value) { + pthread_setspecific(key, reinterpret_cast<void*>(value)); +} + +} // namespace internal +} // namespace gwp_asan + +#endif // COMPONENTS_GWP_ASAN_CLIENT_SAMPLING_ALLOCATOR_SHIMS_POSIX_H_
diff --git a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc index 88d1f79..4353209 100644 --- a/components/gwp_asan/client/sampling_allocator_shims_unittest.cc +++ b/components/gwp_asan/client/sampling_allocator_shims_unittest.cc
@@ -31,9 +31,14 @@ static size_t GetAllocatedSize(void *mem) { return _msize(mem); } -#else // defined(OS_WIN) +#elif defined(OS_MACOSX) +#include <malloc/malloc.h> +static size_t GetAllocatedSize(void* mem) { + return malloc_size(mem); +} +#else #error "Needs to be implemented for platform." -#endif // defined(OS_WIN) +#endif namespace gwp_asan { namespace internal { @@ -52,6 +57,16 @@ constexpr int kFailure = 1; class SamplingAllocatorShimsTest : public base::MultiProcessTest { + public: + static void multiprocessTestSetup() { +#if defined(OS_MACOSX) + base::allocator::InitializeAllocatorShim(); +#endif // defined(OS_MACOSX) + crash_reporter::InitializeCrashKeys(); + InstallAllocatorHooks(AllocatorState::kGpaMaxPages, + AllocatorState::kGpaMaxPages, kSamplingFrequency); + } + protected: void runTest(const char* name) { base::Process process = SpawnChild(name); @@ -91,10 +106,9 @@ return false; } -MULTIPROCESS_TEST_MAIN(BasicFunctionality) { - InstallAllocatorHooks(AllocatorState::kGpaMaxPages, - AllocatorState::kGpaMaxPages, kSamplingFrequency); - +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + BasicFunctionality, + SamplingAllocatorShimsTest::multiprocessTestSetup) { const size_t page_size = base::GetPageSize(); int failures = 0; @@ -111,14 +125,17 @@ EXPECT_TRUE( allocationCheck([&] { return _aligned_realloc(nullptr, 123, 16); }, &_aligned_free, &failures)); -#endif +#endif // defined(OS_WIN) -#if !defined(OS_WIN) +#if defined(OS_POSIX) EXPECT_TRUE(allocationCheck( - [&] { return aligned_alloc(page_size, page_size); }, &free, &failures)); - EXPECT_TRUE(allocationCheck([&] { return aligned_alloc(1, page_size); }, - &free, &failures)); -#endif + [&] { + void* ptr; + posix_memalign(&ptr, page_size, page_size); + return ptr; + }, + &free, &failures)); +#endif // defined(OS_POSIX) EXPECT_TRUE(allocationCheck([&] { return std::malloc(page_size); }, &std::free, &failures)); @@ -150,10 +167,9 @@ runTest("BasicFunctionality"); } -MULTIPROCESS_TEST_MAIN(Realloc) { - InstallAllocatorHooks(AllocatorState::kGpaMaxPages, - AllocatorState::kGpaMaxPages, kSamplingFrequency); - +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + Realloc, + SamplingAllocatorShimsTest::multiprocessTestSetup) { void* alloc = GetGpaForTesting().Allocate(base::GetPageSize()); CHECK_NE(alloc, nullptr); @@ -177,10 +193,9 @@ runTest("Realloc"); } -MULTIPROCESS_TEST_MAIN(Calloc) { - InstallAllocatorHooks(AllocatorState::kGpaMaxPages, - AllocatorState::kGpaMaxPages, kSamplingFrequency); - +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + Calloc, + SamplingAllocatorShimsTest::multiprocessTestSetup) { for (size_t i = 0; i < kLoopIterations; i++) { unsigned char* alloc = static_cast<unsigned char*>(calloc(base::GetPageSize(), 1)); @@ -206,10 +221,9 @@ // GetCrashKeyValue() operates on a per-component basis, can't read the crash // key from the gwp_asan_client component in a component build. #if !defined(COMPONENT_BUILD) -MULTIPROCESS_TEST_MAIN(CrashKey) { - InstallAllocatorHooks(AllocatorState::kGpaMaxPages, - AllocatorState::kGpaMaxPages, kSamplingFrequency); - +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + CrashKey, + SamplingAllocatorShimsTest::multiprocessTestSetup) { std::string crash_key = crash_reporter::GetCrashKeyValue(kGpaCrashKey); uint64_t value; @@ -227,10 +241,9 @@ } #endif // !defined(COMPONENT_BUILD) -MULTIPROCESS_TEST_MAIN(GetSizeEstimate) { - InstallAllocatorHooks(AllocatorState::kGpaMaxPages, - AllocatorState::kGpaMaxPages, kSamplingFrequency); - +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + GetSizeEstimate, + SamplingAllocatorShimsTest::multiprocessTestSetup) { constexpr size_t kAllocationSize = 123; for (size_t i = 0; i < kLoopIterations; i++) { std::unique_ptr<void, decltype(&free)> alloc(malloc(kAllocationSize), free); @@ -251,11 +264,10 @@ } #if defined(OS_WIN) -MULTIPROCESS_TEST_MAIN(AlignedRealloc) { +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + AlignedRealloc, + SamplingAllocatorShimsTest::multiprocessTestSetup) { // Exercise the _aligned_* shims and ensure that we handle them stably. - InstallAllocatorHooks(AllocatorState::kGpaMaxPages, - AllocatorState::kGpaMaxPages, kSamplingFrequency); - constexpr size_t kAllocationSize = 123; constexpr size_t kAllocationAlignment = 64; for (size_t i = 0; i < kLoopIterations; i++) { @@ -272,7 +284,37 @@ TEST_F(SamplingAllocatorShimsTest, AlignedRealloc) { runTest("AlignedRealloc"); } -#endif +#endif // defined(OS_WIN) + +#if defined(OS_MACOSX) +MULTIPROCESS_TEST_MAIN_WITH_SETUP( + BatchFree, + SamplingAllocatorShimsTest::multiprocessTestSetup) { + void* ptrs[AllocatorState::kGpaMaxPages + 1]; + for (size_t i = 0; i < AllocatorState::kGpaMaxPages; i++) { + ptrs[i] = GetGpaForTesting().Allocate(16); + CHECK(ptrs[i]); + } + // Check that all GPA allocations were consumed. + CHECK_EQ(GetGpaForTesting().Allocate(16), nullptr); + + ptrs[AllocatorState::kGpaMaxPages] = + malloc_zone_malloc(malloc_default_zone(), 16); + CHECK(ptrs[AllocatorState::kGpaMaxPages]); + + malloc_zone_batch_free(malloc_default_zone(), ptrs, + AllocatorState::kGpaMaxPages + 1); + + // Check that GPA allocations were freed. + CHECK(GetGpaForTesting().Allocate(16)); + + return kSuccess; +} + +TEST_F(SamplingAllocatorShimsTest, BatchFree) { + runTest("BatchFree"); +} +#endif // defined(OS_MACOSX) } // namespace
diff --git a/components/invalidation/impl/fcm_invalidator.h b/components/invalidation/impl/fcm_invalidator.h index 1a74535a..92ca158 100644 --- a/components/invalidation/impl/fcm_invalidator.h +++ b/components/invalidation/impl/fcm_invalidator.h
@@ -23,7 +23,7 @@ class FCMSyncNetworkChannel; -// This class inplements the Invalidator interface and serves as a +// This class implements the Invalidator interface and serves as a // bridge betwen invalidation Listener and invalidationr Service. class FCMInvalidator : public Invalidator, public FCMInvalidationListener::Delegate {
diff --git a/components/leveldb_proto/proto_database.h b/components/leveldb_proto/proto_database.h index e8757920..b6675b9 100644 --- a/components/leveldb_proto/proto_database.h +++ b/components/leveldb_proto/proto_database.h
@@ -155,7 +155,11 @@ const std::string& key, typename Callbacks::Internal<T>::GetCallback callback) = 0; - // Asynchronously destroys the database. + // Asynchronously destroys the database. Use this call only if the database + // needs to be destroyed for this particular profile. If the database is no + // longer useful for everyone, the client name must be added to + // |kObsoleteSharedProtoDatabaseClients| to ensure automatic clean up of the + // database from all users. virtual void Destroy(Callbacks::DestroyCallback callback) = 0; protected:
diff --git a/components/leveldb_proto/proto_database_provider.h b/components/leveldb_proto/proto_database_provider.h index c5cb565..90d036d8 100644 --- a/components/leveldb_proto/proto_database_provider.h +++ b/components/leveldb_proto/proto_database_provider.h
@@ -26,12 +26,11 @@ static ProtoDatabaseProvider* Create(const base::FilePath& profile_dir); // |client_namespace| is the unique prefix to be used in the shared database - // if the database returned is a SharedDatabaseClient<T>. - // |type_prefix| is a unique prefix within the |client_namespace| to be used - // in the shared database if the database returned is a - // SharedProtoDatabaseClient<T>. - // |unique_db_dir|: the subdirectory this database should live in within - // the profile directory. + // if the database returned is a SharedDatabaseClient<T>. This name must be + // present in |kCurrentSharedProtoDatabaseClients|. |type_prefix| is a unique + // prefix within the |client_namespace| to be used in the shared database if + // the database returned is a SharedProtoDatabaseClient<T>. |unique_db_dir|: + // the subdirectory this database should live in within the profile directory. // |task_runner|: the SequencedTaskRunner to run all database operations on. // This isn't used by SharedProtoDatabaseClients since all calls using // the SharedProtoDatabase will run on its TaskRunner.
diff --git a/components/leveldb_proto/proto_leveldb_wrapper.cc b/components/leveldb_proto/proto_leveldb_wrapper.cc index 0c9b246..03005fb 100644 --- a/components/leveldb_proto/proto_leveldb_wrapper.cc +++ b/components/leveldb_proto/proto_leveldb_wrapper.cc
@@ -47,6 +47,21 @@ FROM_HERE, base::BindOnce(std::move(callback), success, std::move(keys))); } +void RemoveKeysFromTaskRunner( + LevelDB* database, + const std::string& target_prefix, + const LevelDB::KeyFilter& filter, + const std::string& client_id, + Callbacks::UpdateCallback callback, + scoped_refptr<base::SequencedTaskRunner> callback_task_runner) { + leveldb::Status status; + bool success = database->UpdateWithRemoveFilter(base::StringPairs(), filter, + target_prefix, &status); + ProtoLevelDBWrapperMetrics::RecordUpdate(client_id, success, status); + callback_task_runner->PostTask(FROM_HERE, + base::BindOnce(std::move(callback), success)); +} + } // namespace ProtoLevelDBWrapper::ProtoLevelDBWrapper( @@ -86,16 +101,6 @@ std::move(callback)); } -void ProtoLevelDBWrapper::Destroy(Callbacks::DestroyCallback callback) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(db_); - - base::PostTaskAndReplyWithResult( - task_runner_.get(), FROM_HERE, - base::BindOnce(DestroyFromTaskRunner, base::Unretained(db_), metrics_id_), - std::move(callback)); -} - void ProtoLevelDBWrapper::LoadKeys( typename Callbacks::LoadKeysCallback callback) { LoadKeys(std::string(), std::move(callback)); @@ -111,6 +116,27 @@ base::SequencedTaskRunnerHandle::Get())); } +void ProtoLevelDBWrapper::RemoveKeys(const LevelDB::KeyFilter& filter, + const std::string& target_prefix, + Callbacks::UpdateCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + task_runner_->PostTask( + FROM_HERE, + base::BindOnce(RemoveKeysFromTaskRunner, base::Unretained(db_), + target_prefix, filter, metrics_id_, std::move(callback), + base::SequencedTaskRunnerHandle::Get())); +} + +void ProtoLevelDBWrapper::Destroy(Callbacks::DestroyCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(db_); + + base::PostTaskAndReplyWithResult( + task_runner_.get(), FROM_HERE, + base::BindOnce(DestroyFromTaskRunner, base::Unretained(db_), metrics_id_), + std::move(callback)); +} + void ProtoLevelDBWrapper::SetMetricsId(const std::string& id) { metrics_id_ = id; }
diff --git a/components/leveldb_proto/proto_leveldb_wrapper.h b/components/leveldb_proto/proto_leveldb_wrapper.h index b6bbf84..444451d 100644 --- a/components/leveldb_proto/proto_leveldb_wrapper.h +++ b/components/leveldb_proto/proto_leveldb_wrapper.h
@@ -106,6 +106,10 @@ void GetEntry(const std::string& key, typename Callbacks::Internal<T>::GetCallback callback); + void RemoveKeys(const LevelDB::KeyFilter& filter, + const std::string& target_prefix, + Callbacks::UpdateCallback callback); + void Destroy(Callbacks::DestroyCallback callback); void RunInitCallback(Callbacks::InitCallback callback,
diff --git a/components/leveldb_proto/shared_proto_database.cc b/components/leveldb_proto/shared_proto_database.cc index 831c8176..74911d4 100644 --- a/components/leveldb_proto/shared_proto_database.cc +++ b/components/leveldb_proto/shared_proto_database.cc
@@ -26,13 +26,9 @@ } // namespace -inline void RunInitCallbackOnCallingSequence( - Callbacks::InitCallback callback, - scoped_refptr<base::SequencedTaskRunner> callback_task_runner, - bool success) { - callback_task_runner->PostTask(FROM_HERE, - base::BindOnce(std::move(callback), success)); -} +// static +const base::TimeDelta SharedProtoDatabase::kDelayToClearObsoleteDatabase = + base::TimeDelta::FromSeconds(120); inline void RunInitStatusCallbackOnCallingSequence( Callbacks::InitStatusCallback callback, @@ -193,7 +189,8 @@ false /* corruption */); } -void SharedProtoDatabase::ProcessInitRequests(Enums::InitStatus status) { +void SharedProtoDatabase::ProcessOutstandingInitRequests( + Enums::InitStatus status) { // The pairs are stored as (callback, callback_task_runner). while (!outstanding_init_requests_.empty()) { auto request = std::move(outstanding_init_requests_.front()); @@ -222,7 +219,7 @@ init_status_ = Enums::InitStatus::kError; callback_task_runner->PostTask( FROM_HERE, base::BindOnce(std::move(callback), init_status_)); - ProcessInitRequests(init_status_); + ProcessOutstandingInitRequests(init_status_); return; } @@ -259,7 +256,7 @@ init_status_ = Enums::InitStatus::kError; RunInitStatusCallbackOnCallingSequence( std::move(callback), std::move(callback_task_runner), init_status_); - ProcessInitRequests(init_status_); + ProcessOutstandingInitRequests(init_status_); return; } @@ -322,7 +319,7 @@ init_status_ = Enums::InitStatus::kError; RunInitStatusCallbackOnCallingSequence( std::move(callback), std::move(callback_task_runner), init_status_); - ProcessInitRequests(init_status_); + ProcessOutstandingInitRequests(init_status_); return; } @@ -361,7 +358,7 @@ success ? Enums::InitStatus::kCorrupt : Enums::InitStatus::kError; RunInitStatusCallbackOnCallingSequence( std::move(callback), std::move(callback_task_runner), init_status_); - ProcessInitRequests(init_status_); + ProcessOutstandingInitRequests(init_status_); } void SharedProtoDatabase::OnDatabaseInit( @@ -397,9 +394,26 @@ init_status_ = status; init_state_ = status == Enums::InitStatus::kOK ? InitState::kSuccess : InitState::kFailure; - ProcessInitRequests(status); + callback_task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), status)); + ProcessOutstandingInitRequests(status); + + if (init_state_ == InitState::kSuccess) { + // Create a ProtoLevelDBWrapper just like we create for each client, for + // deleting data from obsolete clients. It is fine to use the same wrapper + // to clear data from all clients. This object will be destroyed after + // clearing data for all these clients. + auto db_wrapper = + std::make_unique<ProtoLevelDBWrapper>(task_runner_, db_.get()); + Callbacks::UpdateCallback obsolete_cleared_callback = base::DoNothing(); + base::SequencedTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + base::BindOnce(&DestroyObsoleteSharedProtoDatabaseClients, + std::move(db_wrapper), + std::move(obsolete_cleared_callback)), + kDelayToClearObsoleteDatabase); + } } SharedProtoDatabase::~SharedProtoDatabase() {
diff --git a/components/leveldb_proto/shared_proto_database.h b/components/leveldb_proto/shared_proto_database.h index 4bd50a0..9e77cf4 100644 --- a/components/leveldb_proto/shared_proto_database.h +++ b/components/leveldb_proto/shared_proto_database.h
@@ -87,6 +87,10 @@ std::string client_name; }; + // Make sure to give enough time after startup so that we have less chance of + // affecting startup or navigations. + static const base::TimeDelta kDelayToClearObsoleteDatabase; + // Private since we only want to create a singleton of it. SharedProtoDatabase( const std::string& client_name, @@ -94,7 +98,7 @@ virtual ~SharedProtoDatabase(); - void ProcessInitRequests(Enums::InitStatus status); + void ProcessOutstandingInitRequests(Enums::InitStatus status); template <typename T> std::unique_ptr<SharedProtoDatabaseClient<T>> GetClientInternal( @@ -167,6 +171,11 @@ LevelDB* GetLevelDBForTesting() const; + scoped_refptr<base::SequencedTaskRunner> database_task_runner_for_testing() + const { + return task_runner_; + } + SEQUENCE_CHECKER(on_task_runner_); InitState init_state_ = InitState::kNone;
diff --git a/components/leveldb_proto/shared_proto_database_client.cc b/components/leveldb_proto/shared_proto_database_client.cc index 0510904..14baa8e 100644 --- a/components/leveldb_proto/shared_proto_database_client.cc +++ b/components/leveldb_proto/shared_proto_database_client.cc
@@ -7,8 +7,36 @@ #include "base/strings/strcat.h" #include "components/leveldb_proto/proto_leveldb_wrapper.h" #include "components/leveldb_proto/shared_proto_database.h" +#include "components/leveldb_proto/shared_proto_database_client_list.h" namespace leveldb_proto { +namespace { +const char* const* g_obsolete_client_list_for_testing = nullptr; + +// Holds the db wrapper alive and callback is called at destruction. This class +// is used to post multiple update tasks on |db_wrapper| and keep the instance +// alive till all the callbacks are returned. +class ObsoleteClientsDbHolder + : public base::RefCounted<ObsoleteClientsDbHolder> { + public: + ObsoleteClientsDbHolder(std::unique_ptr<ProtoLevelDBWrapper> db_wrapper, + Callbacks::UpdateCallback callback) + : success_(true), + owned_db_wrapper_(std::move(db_wrapper)), + callback_(std::move(callback)) {} + + void set_success(bool success) { success_ &= success; } + + private: + friend class RefCounted<ObsoleteClientsDbHolder>; + ~ObsoleteClientsDbHolder() { std::move(callback_).Run(success_); } + + bool success_; + std::unique_ptr<ProtoLevelDBWrapper> owned_db_wrapper_; + Callbacks::UpdateCallback callback_; +}; + +} // namespace std::string StripPrefix(const std::string& key, const std::string& prefix) { return base::StartsWith(key, prefix, base::CompareCase::SENSITIVE) @@ -46,4 +74,35 @@ shared_db->UpdateClientCorruptAsync(client_name, std::move(callback)); } +void DestroyObsoleteSharedProtoDatabaseClients( + std::unique_ptr<ProtoLevelDBWrapper> db_wrapper, + Callbacks::UpdateCallback callback) { + ProtoLevelDBWrapper* db_wrapper_ptr = db_wrapper.get(); + scoped_refptr<ObsoleteClientsDbHolder> db_holder = + new ObsoleteClientsDbHolder(std::move(db_wrapper), std::move(callback)); + + const char* const* list = g_obsolete_client_list_for_testing + ? g_obsolete_client_list_for_testing + : kObsoleteSharedProtoDatabaseClients; + for (size_t i = 0; list[i] != nullptr; ++i) { + // Callback keeps a ref pointer to db_holder alive till the changes are + // done. |db_holder| will be destroyed once all the RemoveKeys() calls + // return. + Callbacks::UpdateCallback callback_wrapper = + base::BindOnce([](scoped_refptr<ObsoleteClientsDbHolder> db_holder, + bool success) { db_holder->set_success(success); }, + db_holder); + // Remove all type prefixes for the client. + // TODO(ssid): Support cleanup of namespaces for clients. This code assumes + // the prefix contains the client namespace at the beginning. + db_wrapper_ptr->RemoveKeys( + base::BindRepeating([](const std::string& key) { return true; }), + list[i], std::move(callback_wrapper)); + } +} + +void SetObsoleteClientListForTesting(const char* const* list) { + g_obsolete_client_list_for_testing = list; +} + } // namespace leveldb_proto
diff --git a/components/leveldb_proto/shared_proto_database_client.h b/components/leveldb_proto/shared_proto_database_client.h index 8995fe7..fd11d224 100644 --- a/components/leveldb_proto/shared_proto_database_client.h +++ b/components/leveldb_proto/shared_proto_database_client.h
@@ -40,9 +40,21 @@ const std::string& client_name, ClientCorruptCallback callback); +// Destroys all the data from obsolete clients, for the given |db_wrapper| +// instance. |callback| is called once all the obsolete clients data are +// removed, with failure status if one or more of the update fails. +void DestroyObsoleteSharedProtoDatabaseClients( + std::unique_ptr<ProtoLevelDBWrapper> db_wrapper, + Callbacks::UpdateCallback callback); + +// Sets list of client names that are obsolete and will be cleared by next call +// to DestroyObsoleteSharedProtoDatabaseClients(). |list| is list of c strings +// with a nullptr to mark the end of list. +void SetObsoleteClientListForTesting(const char* const* list); + // An implementation of ProtoDatabase<T> that uses a shared LevelDB and task // runner. -// Should be created, destroyed, and used on the same thread. +// Should be created, destroyed, and used on the same sequenced task runner. template <typename T> class SharedProtoDatabaseClient : public ProtoDatabase<T> { public:
diff --git a/components/leveldb_proto/shared_proto_database_client_list.cc b/components/leveldb_proto/shared_proto_database_client_list.cc index 216f4c2..9019b6a15 100644 --- a/components/leveldb_proto/shared_proto_database_client_list.cc +++ b/components/leveldb_proto/shared_proto_database_client_list.cc
@@ -12,22 +12,6 @@ namespace leveldb_proto { -const char kFeatureEngagementClientName[] = "FeatureEngagement"; - -const char* const kCurrentSharedProtoDatabaseClients[] = { - kFeatureEngagementClientName, -}; -const size_t kCurrentSharedProtoDatabaseClientsLength = - base::size(kCurrentSharedProtoDatabaseClients); - -#ifdef SHARED_PROTO_DATABASE_CLIENT_LIST_USE_OBSOLETE_CLIENT_LIST -const char* const kObsoleteSharedProtoDatabaseClients[] = { - /* Add obsolete clients here. */ -}; -const size_t kObsoleteSharedProtoDatabaseClientsLength = - base::size(kObsoleteSharedProtoDatabaseClients); -#endif // SHARED_PROTO_DATABASE_CLIENT_LIST_USE_OBSOLETE_CLIENT_LIST - // static bool SharedProtoDatabaseClientList::ShouldUseSharedDB( const std::string& client_name) {
diff --git a/components/leveldb_proto/shared_proto_database_client_list.h b/components/leveldb_proto/shared_proto_database_client_list.h index 5644a2d..59ef09e 100644 --- a/components/leveldb_proto/shared_proto_database_client_list.h +++ b/components/leveldb_proto/shared_proto_database_client_list.h
@@ -11,15 +11,19 @@ namespace leveldb_proto { -extern const char kFeatureEngagementClientName[]; +const char* const kFeatureEngagementName = "FeatureEngagement"; -extern const char* const kCurrentSharedProtoDatabaseClients[]; -extern const size_t kCurrentSharedProtoDatabaseClientsLength; +// NOTE: The client names should not have partial or complete prefix overlap +// with any other client name, current or obsolete. Internally the stored data +// is grouped by the prefix of client name. These names cannot be renamed +// without adding the old name to obsolete client list and such rename would +// make the client be treated as a new client. +const char* const kCurrentSharedProtoDatabaseClients[] = { + kFeatureEngagementName, nullptr}; -#ifdef SHARED_PROTO_DATABASE_CLIENT_LIST_USE_OBSOLETE_CLIENT_LIST -extern const char* const kObsoleteSharedProtoDatabaseClients[]; -extern const size_t kObsoleteSharedProtoDatabaseClientsLength; -#endif // SHARED_PROTO_DATABASE_CLIENT_LIST_USE_OBSOLETE_CLIENT_LIST +const char* const kObsoleteSharedProtoDatabaseClients[] = { + nullptr // Marks the last element. +}; class SharedProtoDatabaseClientList { public:
diff --git a/components/leveldb_proto/shared_proto_database_client_unittest.cc b/components/leveldb_proto/shared_proto_database_client_unittest.cc index 3f0e996..267f70e 100644 --- a/components/leveldb_proto/shared_proto_database_client_unittest.cc +++ b/components/leveldb_proto/shared_proto_database_client_unittest.cc
@@ -20,9 +20,10 @@ namespace { -const std::string kDefaultNamespace = "ns"; -const std::string kDefaultNamespace2 = "ns2"; -const std::string kDefaultTypePrefix = "tp"; +const char* kDefaultNamespace = "abc"; +const char* kDefaultNamespace1 = "cde"; +const char* kDefaultNamespace2 = "cfd"; +const char* kDefaultTypePrefix = "tp"; } // namespace @@ -40,6 +41,7 @@ temp_dir_.reset(); } + protected: scoped_refptr<SharedProtoDatabase> db() { return db_; } base::ScopedTempDir* temp_dir() { return temp_dir_.get(); } @@ -235,6 +237,26 @@ destroy_loop.Run(); } + // Sets the obsolete client list to given list, runs clean up tasks and waits + // for them to complete. + void DestroyObsoleteClientsAndWait(const char* const* client_list) { + SetObsoleteClientListForTesting(client_list); + base::RunLoop wait_loop; + Callbacks::UpdateCallback wait_callback = base::BindOnce( + [](base::OnceClosure closure, bool success) { + EXPECT_TRUE(success); + std::move(closure).Run(); + }, + wait_loop.QuitClosure()); + + DestroyObsoleteSharedProtoDatabaseClients( + std::make_unique<ProtoLevelDBWrapper>( + db_->database_task_runner_for_testing(), GetLevelDB()), + std::move(wait_callback)); + wait_loop.Run(); + SetObsoleteClientListForTesting(nullptr); + } + private: base::test::ScopedTaskEnvironment scoped_task_environment_; @@ -463,6 +485,61 @@ } } +TEST_F(SharedProtoDatabaseClientTest, TestCleanupObsoleteClients) { + auto status = Enums::InitStatus::kError; + auto client_a = + GetClientAndWait<TestProto>(kDefaultNamespace, kDefaultTypePrefix, + true /* create_if_missing */, &status); + ASSERT_EQ(status, Enums::InitStatus::kOK); + auto client_b = + GetClientAndWait<TestProto>(kDefaultNamespace1, kDefaultTypePrefix, + true /* create_if_missing */, &status); + ASSERT_EQ(status, Enums::InitStatus::kOK); + auto client_c = + GetClientAndWait<TestProto>(kDefaultNamespace2, kDefaultTypePrefix, + true /* create_if_missing */, &status); + ASSERT_EQ(status, Enums::InitStatus::kOK); + + std::vector<std::string> test_keys = {"a", "b", "c"}; + UpdateEntries(client_a.get(), test_keys, leveldb_proto::KeyVector(), true); + UpdateEntries(client_b.get(), test_keys, leveldb_proto::KeyVector(), true); + UpdateEntries(client_c.get(), test_keys, leveldb_proto::KeyVector(), true); + + // Check that the original list does not clear any data from test DBs. + DestroyObsoleteClientsAndWait(nullptr /* client_list */); + + std::vector<std::string> keys; + LevelDB* db = GetLevelDB(); + db->LoadKeys(&keys); + EXPECT_EQ(keys.size(), test_keys.size() * 3); + + // Mark some DBs obsolete. + const char* const kObsoleteList1[] = {kDefaultNamespace, kDefaultNamespace1, + nullptr}; + DestroyObsoleteClientsAndWait(kObsoleteList1); + + keys.clear(); + db->LoadKeys(&keys); + + EXPECT_EQ(keys.size(), test_keys.size()); + EXPECT_FALSE( + ContainsKeys(keys, test_keys, kDefaultNamespace, kDefaultTypePrefix)); + EXPECT_FALSE( + ContainsKeys(keys, test_keys, kDefaultNamespace1, kDefaultTypePrefix)); + EXPECT_TRUE( + ContainsKeys(keys, test_keys, kDefaultNamespace2, kDefaultTypePrefix)); + + // Make all the DBs obsolete. + const char* const kObsoleteList2[] = {kDefaultNamespace, kDefaultNamespace1, + kDefaultNamespace2, nullptr}; + DestroyObsoleteClientsAndWait(kObsoleteList2); + + // Nothing should remain. + keys.clear(); + db->LoadKeys(&keys); + EXPECT_EQ(keys.size(), 0U); +} + TEST_F(SharedProtoDatabaseClientTest, TestDestroy) { auto status = Enums::InitStatus::kError; auto client_a =
diff --git a/components/leveldb_proto/unique_proto_database.h b/components/leveldb_proto/unique_proto_database.h index 50b6a3c5..85c0b09 100644 --- a/components/leveldb_proto/unique_proto_database.h +++ b/components/leveldb_proto/unique_proto_database.h
@@ -96,6 +96,10 @@ void Destroy(Callbacks::DestroyCallback callback) override; + void RemoveKeysForTesting(const LevelDB::KeyFilter& key_filter, + const std::string& target_prefix, + Callbacks::UpdateCallback callback); + bool GetApproximateMemoryUse(uint64_t* approx_mem_use); // Sets the identifier used by the underlying LevelDB wrapper to record @@ -282,6 +286,14 @@ } template <typename T> +void UniqueProtoDatabase<T>::RemoveKeysForTesting( + const LevelDB::KeyFilter& key_filter, + const std::string& target_prefix, + Callbacks::UpdateCallback callback) { + db_wrapper_->RemoveKeys(key_filter, target_prefix, std::move(callback)); +} + +template <typename T> bool UniqueProtoDatabase<T>::GetApproximateMemoryUse(uint64_t* approx_mem_use) { return db_wrapper_->GetApproximateMemoryUse(approx_mem_use); }
diff --git a/components/leveldb_proto/unique_proto_database_unittest.cc b/components/leveldb_proto/unique_proto_database_unittest.cc index c867056..7c755f1e 100644 --- a/components/leveldb_proto/unique_proto_database_unittest.cc +++ b/components/leveldb_proto/unique_proto_database_unittest.cc
@@ -59,6 +59,11 @@ bool(const base::StringPairs&, const KeyFilter&, leveldb::Status*)); + MOCK_METHOD4(UpdateWithRemoveFilter, + bool(const base::StringPairs&, + const KeyFilter&, + const std::string&, + leveldb::Status*)); MOCK_METHOD1(Load, bool(std::vector<std::string>*)); MOCK_METHOD2(LoadWithFilter, bool(const KeyFilter&, std::vector<std::string>*)); @@ -151,8 +156,6 @@ return key == "0"; } -} // namespace - EntryMap GetSmallModel() { EntryMap model; @@ -168,6 +171,8 @@ return model; } +} // namespace + void ExpectEntryPointersEquals(EntryMap expected, const std::vector<TestProto>& actual) { EXPECT_EQ(expected.size(), actual.size()); @@ -405,6 +410,36 @@ base::RunLoop().RunUntilIdle(); } +TEST_F(UniqueProtoDatabaseTest, TestDBRemoveKeys) { + const std::string kTestPrefix = "test_prefix"; + base::FilePath path(FILE_PATH_LITERAL("/fake/path")); + + auto mock_db = std::make_unique<MockDB>(); + MockDatabaseCaller caller; + + EXPECT_CALL(*mock_db, Init(_, options_, _)); + EXPECT_CALL(*mock_db, UpdateWithRemoveFilter(_, _, kTestPrefix, _)) + .WillOnce(Return(true)); + EXPECT_CALL(caller, InitStatusCallback(_)); + db_->InitWithDatabase(mock_db.get(), path, CreateSimpleOptions(), + base::BindOnce(&MockDatabaseCaller::InitStatusCallback, + base::Unretained(&caller))); + + base::RunLoop().RunUntilIdle(); + + base::RunLoop run_update_entries; + auto expect_update_success = base::BindOnce( + [](base::OnceClosure signal, bool success) { + EXPECT_TRUE(success); + std::move(signal).Run(); + }, + run_update_entries.QuitClosure()); + db_->RemoveKeysForTesting( + base::BindRepeating([](const std::string& str) { return true; }), + kTestPrefix, std::move(expect_update_success)); + run_update_entries.Run(); +} + class UniqueProtoDatabaseLevelDBTest : public testing::Test { public: void TearDown() override { base::RunLoop().RunUntilIdle(); }
diff --git a/components/omnibox/browser/autocomplete_match.h b/components/omnibox/browser/autocomplete_match.h index 4d443e5..dfc1313e 100644 --- a/components/omnibox/browser/autocomplete_match.h +++ b/components/omnibox/browser/autocomplete_match.h
@@ -483,6 +483,9 @@ // it! base::string16 keyword; + // Set in matches originating from keyword results. + bool from_keyword; + // Set to a matching pedal if appropriate. The pedal is not owned, and the // owning OmniboxPedalProvider must outlive this. OmniboxPedal* pedal = nullptr;
diff --git a/components/omnibox/browser/base_search_provider.cc b/components/omnibox/browser/base_search_provider.cc index 7f4dab29..448a426 100644 --- a/components/omnibox/browser/base_search_provider.cc +++ b/components/omnibox/browser/base_search_provider.cc
@@ -151,7 +151,7 @@ AutocompleteMatch BaseSearchProvider::CreateSearchSuggestion( const base::string16& suggestion, AutocompleteMatchType::Type type, - bool from_keyword_provider, + bool from_keyword, const TemplateURL* template_url, const SearchTermsData& search_terms_data) { // These calls use a number of default values. For instance, they assume @@ -159,13 +159,13 @@ // mode. They also assume the caller knows what it's doing and we set // this match to look as if it was received/created synchronously. SearchSuggestionParser::SuggestResult suggest_result( - suggestion, type, /*subtype_identifier=*/0, from_keyword_provider, + suggestion, type, /*subtype_identifier=*/0, from_keyword, /*relevance=*/0, /*relevance_from_server=*/false, /*input_text=*/base::string16()); suggest_result.set_received_after_last_keystroke(false); - return CreateSearchSuggestion(nullptr, AutocompleteInput(), - from_keyword_provider, suggest_result, - template_url, search_terms_data, 0, false); + return CreateSearchSuggestion(nullptr, AutocompleteInput(), from_keyword, + suggest_result, template_url, search_terms_data, + 0, false); } // static @@ -289,15 +289,18 @@ const base::string16 input_lower = base::i18n::ToLower(input.text()); // suggestion.match_contents() should have already been collapsed. match.allowed_to_be_default_match = - (!in_keyword_mode || suggestion.from_keyword_provider()) && + (!in_keyword_mode || suggestion.from_keyword()) && (base::CollapseWhitespace(input_lower, false) == base::i18n::ToLower(suggestion.match_contents())); + if (suggestion.from_keyword()) + match.from_keyword = true; + // We only allow inlinable navsuggestions that were received before the // last keystroke because we don't want asynchronous inline autocompletions. if (!input.prevent_inline_autocomplete() && !suggestion.received_after_last_keystroke() && - (!in_keyword_mode || suggestion.from_keyword_provider()) && + (!in_keyword_mode || suggestion.from_keyword()) && base::StartsWith( base::i18n::ToLower(suggestion.suggestion()), input_lower, base::CompareCase::SENSITIVE)) { @@ -330,8 +333,8 @@ *match.search_terms_args, search_terms_data)); // Search results don't look like URLs. - match.transition = suggestion.from_keyword_provider() ? - ui::PAGE_TRANSITION_KEYWORD : ui::PAGE_TRANSITION_GENERATED; + match.transition = suggestion.from_keyword() ? ui::PAGE_TRANSITION_KEYWORD + : ui::PAGE_TRANSITION_GENERATED; return match; } @@ -342,7 +345,7 @@ const TemplateURL* template_url) { base::string16 fill_into_edit; - if (suggest_result.from_keyword_provider()) + if (suggest_result.from_keyword()) fill_into_edit.append(template_url->keyword() + base::char16(' ')); fill_into_edit.append(suggest_result.suggestion()); @@ -427,8 +430,8 @@ bool in_keyword_mode, MatchMap* map) { AutocompleteMatch match = CreateSearchSuggestion( - this, GetInput(result.from_keyword_provider()), in_keyword_mode, result, - GetTemplateURL(result.from_keyword_provider()), + this, GetInput(result.from_keyword()), in_keyword_mode, result, + GetTemplateURL(result.from_keyword()), client_->GetTemplateURLService()->search_terms_data(), accepted_suggestion, ShouldAppendExtraParams(result)); if (!match.destination_url.is_valid())
diff --git a/components/omnibox/browser/keyword_provider.cc b/components/omnibox/browser/keyword_provider.cc index db34490..a3a1a95 100644 --- a/components/omnibox/browser/keyword_provider.cc +++ b/components/omnibox/browser/keyword_provider.cc
@@ -482,6 +482,7 @@ FillInURLAndContents(remaining_input, template_url, &match); match.keyword = keyword; + match.from_keyword = true; match.transition = ui::PAGE_TRANSITION_KEYWORD; return match;
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc index b199ce57..c0a17d1 100644 --- a/components/omnibox/browser/omnibox_edit_model.cc +++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -743,8 +743,9 @@ fake_single_entry_result.AppendMatches(input_, fake_single_entry_matches); OmniboxLog log( input_.from_omnibox_focus() ? base::string16() : input_text, - just_deleted_text_, input_.type(), popup_open, - dropdown_ignored ? 0 : index, disposition, !pasted_text.empty(), + just_deleted_text_, input_.type(), is_keyword_selected(), + keyword_mode_entry_method_, popup_open, dropdown_ignored ? 0 : index, + disposition, !pasted_text.empty(), SessionID::InvalidValue(), // don't know tab ID; set later if appropriate ClassifyPage(), elapsed_time_since_user_first_modified_omnibox, match.allowed_to_be_default_match ? match.inline_autocompletion.length()
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h index 6d4e1220..d01e927 100644 --- a/components/omnibox/browser/omnibox_edit_model.h +++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -68,6 +68,8 @@ OmniboxFocusState focus_state; FocusSource focus_source; const AutocompleteInput autocomplete_input; + private: + DISALLOW_ASSIGN(State); }; // This is a mirror of content::kMaxURLDisplayChars because ios cannot depend
diff --git a/components/omnibox/browser/omnibox_log.cc b/components/omnibox/browser/omnibox_log.cc index a35231e..4270b56 100644 --- a/components/omnibox/browser/omnibox_log.cc +++ b/components/omnibox/browser/omnibox_log.cc
@@ -8,6 +8,8 @@ const base::string16& text, bool just_deleted_text, metrics::OmniboxInputType input_type, + bool in_keyword_mode, + metrics::OmniboxEventProto::KeywordModeEntryMethod entry_method, bool is_popup_open, size_t selected_index, WindowOpenDisposition disposition, @@ -21,6 +23,8 @@ : text(text), just_deleted_text(just_deleted_text), input_type(input_type), + in_keyword_mode(in_keyword_mode), + keyword_mode_entry_method(entry_method), is_popup_open(is_popup_open), selected_index(selected_index), disposition(disposition),
diff --git a/components/omnibox/browser/omnibox_log.h b/components/omnibox/browser/omnibox_log.h index ab7ebd6..bbb7b5d 100644 --- a/components/omnibox/browser/omnibox_log.h +++ b/components/omnibox/browser/omnibox_log.h
@@ -23,6 +23,8 @@ OmniboxLog(const base::string16& text, bool just_deleted_text, metrics::OmniboxInputType input_type, + bool in_keyword_mode, + metrics::OmniboxEventProto::KeywordModeEntryMethod entry_method, bool is_popup_open, size_t selected_index, WindowOpenDisposition disposition, @@ -46,6 +48,14 @@ // The detected type of the user's input. metrics::OmniboxInputType input_type; + // Whether the Omnibox was in keyword mode when the user selected a + // suggestion. + bool in_keyword_mode; + + // Preserves the method that the user used to enter keyword mode. If + // |in_keyword_mode| is false, this should be INVALID. + metrics::OmniboxEventProto::KeywordModeEntryMethod keyword_mode_entry_method; + // True if the popup is open. bool is_popup_open;
diff --git a/components/omnibox/browser/omnibox_metrics_provider.cc b/components/omnibox/browser/omnibox_metrics_provider.cc index 4a5447a..042602c0 100644 --- a/components/omnibox/browser/omnibox_metrics_provider.cc +++ b/components/omnibox/browser/omnibox_metrics_provider.cc
@@ -11,6 +11,7 @@ #include "base/strings/string16.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" +#include "build/build_config.h" #include "components/metrics/metrics_log.h" #include "components/omnibox/browser/autocomplete_match.h" #include "components/omnibox/browser/autocomplete_provider.h" @@ -169,10 +170,25 @@ if (i->subtype_identifier > 0) suggestion->set_result_subtype_identifier(i->subtype_identifier); suggestion->set_has_tab_match(i->has_tab_match); + // TODO(krb@chromium.org): Try including when libprotobuf is updated. +#if !defined(OS_ANDROID) && !defined(OS_IOS) + suggestion->set_is_keyword_suggestion(i->from_keyword); +#endif } for (auto i(log.providers_info.begin()); i != log.providers_info.end(); ++i) { OmniboxEventProto::ProviderInfo* provider_info = omnibox_event->add_provider_info(); provider_info->CopyFrom(*i); } +#if !defined(OS_ANDROID) && !defined(OS_IOS) + omnibox_event->set_in_keyword_mode(log.in_keyword_mode); + if (log.in_keyword_mode) { + if (metrics::OmniboxEventProto_KeywordModeEntryMethod_IsValid( + log.keyword_mode_entry_method)) + omnibox_event->set_keyword_mode_entry_method( + log.keyword_mode_entry_method); + else + omnibox_event->set_keyword_mode_entry_method(OmniboxEventProto::INVALID); + } +#endif }
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc index 42299c5..3d63271 100644 --- a/components/omnibox/browser/search_provider.cc +++ b/components/omnibox/browser/search_provider.cc
@@ -340,8 +340,7 @@ bool SearchProvider::ShouldAppendExtraParams( const SearchSuggestionParser::SuggestResult& result) const { - return !result.from_keyword_provider() || - providers_.default_provider().empty(); + return !result.from_keyword() || providers_.default_provider().empty(); } void SearchProvider::RecordDeletionResult(bool success) { @@ -1001,8 +1000,8 @@ SearchSuggestionParser::SuggestResult verbatim( /*suggestion=*/trimmed_verbatim, AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED, - /*subtype_identifier=*/0, /*from_keyword_provider=*/false, - verbatim_relevance, relevance_from_server, + /*subtype_identifier=*/0, /*from_keyword=*/false, verbatim_relevance, + relevance_from_server, /*input_text=*/trimmed_verbatim); if (has_answer) verbatim.SetAnswer(answer); @@ -1027,7 +1026,7 @@ SearchSuggestionParser::SuggestResult verbatim( /*suggestion=*/trimmed_verbatim, AutocompleteMatchType::SEARCH_OTHER_ENGINE, - /*subtype_identifier=*/0, /*from_keyword_provider=*/true, + /*subtype_identifier=*/0, /*from_keyword=*/true, keyword_verbatim_relevance, keyword_relevance_from_server, /*input_text=*/trimmed_verbatim); AddMatchToMap(verbatim, std::string(), @@ -1436,10 +1435,10 @@ AutocompleteMatch SearchProvider::NavigationToMatch( const SearchSuggestionParser::NavigationResult& navigation) { base::string16 input; - const bool trimmed_whitespace = base::TrimWhitespace( - navigation.from_keyword_provider() ? - keyword_input_.text() : input_.text(), - base::TRIM_TRAILING, &input) != base::TRIM_NONE; + const bool trimmed_whitespace = + base::TrimWhitespace( + navigation.from_keyword() ? keyword_input_.text() : input_.text(), + base::TRIM_TRAILING, &input) != base::TRIM_NONE; AutocompleteMatch match(this, navigation.relevance(), false, navigation.type()); match.destination_url = navigation.url(); @@ -1501,6 +1500,8 @@ navigation.relevance_from_server() ? kTrue : kFalse); match.RecordAdditionalInfo(kShouldPrefetchKey, kFalse); + match.from_keyword = navigation.from_keyword(); + return match; }
diff --git a/components/omnibox/browser/search_suggestion_parser.cc b/components/omnibox/browser/search_suggestion_parser.cc index d1036c5..d7b8558 100644 --- a/components/omnibox/browser/search_suggestion_parser.cc +++ b/components/omnibox/browser/search_suggestion_parser.cc
@@ -59,13 +59,13 @@ // SearchSuggestionParser::Result ---------------------------------------------- -SearchSuggestionParser::Result::Result(bool from_keyword_provider, +SearchSuggestionParser::Result::Result(bool from_keyword, int relevance, bool relevance_from_server, AutocompleteMatchType::Type type, int subtype_identifier, const std::string& deletion_url) - : from_keyword_provider_(from_keyword_provider), + : from_keyword_(from_keyword), type_(type), subtype_identifier_(subtype_identifier), relevance_(relevance), @@ -83,7 +83,7 @@ const base::string16& suggestion, AutocompleteMatchType::Type type, int subtype_identifier, - bool from_keyword_provider, + bool from_keyword, int relevance, bool relevance_from_server, const base::string16& input_text) @@ -97,7 +97,7 @@ /*deletion_url=*/"", /*image_dominant_color=*/"", /*image_url=*/"", - from_keyword_provider, + from_keyword, relevance, relevance_from_server, /*should_prefetch=*/false, @@ -114,12 +114,12 @@ const std::string& deletion_url, const std::string& image_dominant_color, const std::string& image_url, - bool from_keyword_provider, + bool from_keyword, int relevance, bool relevance_from_server, bool should_prefetch, const base::string16& input_text) - : Result(from_keyword_provider, + : Result(from_keyword, relevance, relevance_from_server, type, @@ -194,7 +194,7 @@ int SearchSuggestionParser::SuggestResult::CalculateRelevance( const AutocompleteInput& input, bool keyword_provider_requested) const { - if (!from_keyword_provider_ && keyword_provider_requested) + if (!from_keyword_ && keyword_provider_requested) return 100; return ((input.type() == metrics::OmniboxInputType::URL) ? 300 : 600); } @@ -208,11 +208,11 @@ int subtype_identifier, const base::string16& description, const std::string& deletion_url, - bool from_keyword_provider, + bool from_keyword, int relevance, bool relevance_from_server, const base::string16& input_text) - : Result(from_keyword_provider, + : Result(from_keyword, relevance, relevance_from_server, type, @@ -285,7 +285,7 @@ int SearchSuggestionParser::NavigationResult::CalculateRelevance( const AutocompleteInput& input, bool keyword_provider_requested) const { - return (from_keyword_provider_ || !keyword_provider_requested) ? 800 : 150; + return (from_keyword_ || !keyword_provider_requested) ? 800 : 150; } // SearchSuggestionParser::Results ---------------------------------------------
diff --git a/components/omnibox/browser/search_suggestion_parser.h b/components/omnibox/browser/search_suggestion_parser.h index 75fbc63b..45d2040 100644 --- a/components/omnibox/browser/search_suggestion_parser.h +++ b/components/omnibox/browser/search_suggestion_parser.h
@@ -42,7 +42,7 @@ // highly fragmented SearchProvider logic for each Result type. class Result { public: - Result(bool from_keyword_provider, + Result(bool from_keyword, int relevance, bool relevance_from_server, AutocompleteMatchType::Type type, @@ -51,7 +51,7 @@ Result(const Result& other); virtual ~Result(); - bool from_keyword_provider() const { return from_keyword_provider_; } + bool from_keyword() const { return from_keyword_; } const base::string16& match_contents() const { return match_contents_; } const ACMatchClassifications& match_contents_class() const { @@ -89,8 +89,8 @@ base::string16 match_contents_; ACMatchClassifications match_contents_class_; - // True if the result came from the keyword provider. - bool from_keyword_provider_; + // True if the result came from a keyword suggestion. + bool from_keyword_; AutocompleteMatchType::Type type_; @@ -127,7 +127,7 @@ SuggestResult(const base::string16& suggestion, AutocompleteMatchType::Type type, int subtype_identifier, - bool from_keyword_provider, + bool from_keyword, int relevance, bool relevance_from_server, const base::string16& input_text); @@ -141,7 +141,7 @@ const std::string& deletion_url, const std::string& image_dominant_color, const std::string& image_url, - bool from_keyword_provider, + bool from_keyword, int relevance, bool relevance_from_server, bool should_prefetch, @@ -220,7 +220,7 @@ int subtype_identifier, const base::string16& description, const std::string& deletion_url, - bool from_keyword_provider, + bool from_keyword, int relevance, bool relevance_from_server, const base::string16& input_text);
diff --git a/components/omnibox/browser/shortcuts_provider.cc b/components/omnibox/browser/shortcuts_provider.cc index 6de34c0..837a5ba 100644 --- a/components/omnibox/browser/shortcuts_provider.cc +++ b/components/omnibox/browser/shortcuts_provider.cc
@@ -33,6 +33,7 @@ #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/omnibox/browser/url_prefix.h" #include "components/prefs/pref_service.h" +#include "components/search_engines/template_url_service.h" #include "components/url_formatter/url_fixer.h" #include "third_party/metrics_proto/omnibox_input_type.pb.h" #include "url/third_party/mozilla/url_parse.h" @@ -290,16 +291,26 @@ DCHECK(is_search_type != match.keyword.empty()); + const bool keyword_matches = + base::StartsWith(base::UTF16ToUTF8(input.text()), + base::StrCat({base::UTF16ToUTF8(match.keyword), " "}), + base::CompareCase::INSENSITIVE_ASCII); + if (is_search_type) { + match.from_keyword = + // Either the match is not from the default search provider: + match.keyword != client_->GetTemplateURLService() + ->GetDefaultSearchProvider() + ->keyword() || + // Or it is, but keyword mode was invoked explicitly and the keyword + // in the input is also of the default search provider. + (input.prefer_keyword() && keyword_matches); + } // True if input is in keyword mode and the match is a URL suggestion or the // match has a different keyword. - bool would_cause_leaving_keyboard_mode = - input.prefer_keyword() && - (!is_search_type || - !base::StartsWith(base::UTF16ToUTF8(input.text()), - base::StrCat({base::UTF16ToUTF8(match.keyword), " "}), - base::CompareCase::INSENSITIVE_ASCII)); + bool would_cause_leaving_keyword_mode = + input.prefer_keyword() && !(is_search_type && keyword_matches); - if (!would_cause_leaving_keyboard_mode) { + if (!would_cause_leaving_keyword_mode) { if (is_search_type) { if (match.fill_into_edit.size() >= input.text().size() && std::equal(match.fill_into_edit.begin(),
diff --git a/components/omnibox/bug-triage.md b/components/omnibox/bug-triage.md index 44f94028..f4d0e34 100644 --- a/components/omnibox/bug-triage.md +++ b/components/omnibox/bug-triage.md
@@ -115,7 +115,7 @@ policies](https://www.chromium.org/for-testers/bug-reporting-guidelines/triage-best-practices). *Priority-2* represents wanted for this release but can be punted for a release. *Priority-3* are bugs not time sensitive. There is an even-lower-priority -state; see the *NextAction=01/08/2019* below. +state; see the *NextAction=01/07/2020* below. If you aren't sure of the scope, severity, or implications of an issue, prefer to assign it a higher priority (*1* or *2*) and try to assign it to someone
diff --git a/components/open_from_clipboard/BUILD.gn b/components/open_from_clipboard/BUILD.gn index 73e360e..2f9fa810 100644 --- a/components/open_from_clipboard/BUILD.gn +++ b/components/open_from_clipboard/BUILD.gn
@@ -40,6 +40,8 @@ assert_no_deps = [ "//base:i18n" ] if (is_ios) { configs += [ "//build/config/compiler:enable_arc" ] + + libs = [ "MobileCoreServices.framework" ] } } @@ -53,6 +55,7 @@ deps = [ ":open_from_clipboard", "//base", + "//ui/gfx:gfx", "//url", ] }
diff --git a/components/open_from_clipboard/DEPS b/components/open_from_clipboard/DEPS index d80a9dc..9433bfe 100644 --- a/components/open_from_clipboard/DEPS +++ b/components/open_from_clipboard/DEPS
@@ -3,4 +3,5 @@ "+net", "+ui/base/clipboard", "+ui/base/test", + "+ui/gfx/image", ]
diff --git a/components/open_from_clipboard/clipboard_recent_content.h b/components/open_from_clipboard/clipboard_recent_content.h index 48063e8..11d25d18 100644 --- a/components/open_from_clipboard/clipboard_recent_content.h +++ b/components/open_from_clipboard/clipboard_recent_content.h
@@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/time/time.h" +#include "ui/gfx/image/image.h" #include "url/gurl.h" // Helper class returning an URL if the content of the clipboard can be turned @@ -36,6 +37,10 @@ // is recent enough and has not been suppressed. virtual base::Optional<base::string16> GetRecentTextFromClipboard() = 0; + // Returns clipboard content as image, if it has a compatible type, + // is recent enough and has not been suppressed. + virtual base::Optional<gfx::Image> GetRecentImageFromClipboard() = 0; + // Returns how old the content of the clipboard is. virtual base::TimeDelta GetClipboardContentAge() const = 0;
diff --git a/components/open_from_clipboard/clipboard_recent_content_generic.cc b/components/open_from_clipboard/clipboard_recent_content_generic.cc index 0877cbb..0ca6a01 100644 --- a/components/open_from_clipboard/clipboard_recent_content_generic.cc +++ b/components/open_from_clipboard/clipboard_recent_content_generic.cc
@@ -68,6 +68,11 @@ return base::nullopt; } +base::Optional<gfx::Image> +ClipboardRecentContentGeneric::GetRecentImageFromClipboard() { + return base::nullopt; +} + base::TimeDelta ClipboardRecentContentGeneric::GetClipboardContentAge() const { const base::Time last_modified_time = ui::Clipboard::GetForCurrentThread()->GetLastModifiedTime();
diff --git a/components/open_from_clipboard/clipboard_recent_content_generic.h b/components/open_from_clipboard/clipboard_recent_content_generic.h index 38422d7..8005485 100644 --- a/components/open_from_clipboard/clipboard_recent_content_generic.h +++ b/components/open_from_clipboard/clipboard_recent_content_generic.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "components/open_from_clipboard/clipboard_recent_content.h" +#include "ui/gfx/image/image.h" #include "url/gurl.h" // An implementation of ClipboardRecentContent that uses @@ -24,6 +25,7 @@ // ClipboardRecentContent implementation. base::Optional<GURL> GetRecentURLFromClipboard() override; base::Optional<base::string16> GetRecentTextFromClipboard() override; + base::Optional<gfx::Image> GetRecentImageFromClipboard() override; base::TimeDelta GetClipboardContentAge() const override; void SuppressClipboardContent() override;
diff --git a/components/open_from_clipboard/clipboard_recent_content_impl_ios.h b/components/open_from_clipboard/clipboard_recent_content_impl_ios.h index da54ba1..0cc789a 100644 --- a/components/open_from_clipboard/clipboard_recent_content_impl_ios.h +++ b/components/open_from_clipboard/clipboard_recent_content_impl_ios.h
@@ -6,6 +6,7 @@ #define COMPONENTS_OPEN_FROM_CLIPBOARD_CLIPBOARD_RECENT_CONTENT_IMPL_IOS_H_ #import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> // A protocol implemented by delegates to handle clipboard changes. @protocol ClipboardRecentContentDelegate<NSObject> @@ -39,6 +40,10 @@ // not been suppresed. Otherwise, returns nil. - (NSString*)recentTextFromClipboard; +// Returns the copied string if the clipboard contains a recent string that has +// not been suppressed. Otherwise, returns nil. +- (UIImage*)recentImageFromClipboard; + // Returns how old the content of the clipboard is. - (NSTimeInterval)clipboardContentAge;
diff --git a/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm b/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm index f8353ea..7043afd 100644 --- a/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm +++ b/components/open_from_clipboard/clipboard_recent_content_impl_ios.mm
@@ -5,6 +5,7 @@ #import "components/open_from_clipboard/clipboard_recent_content_impl_ios.h" #import <CommonCrypto/CommonDigest.h> +#import <MobileCoreServices/MobileCoreServices.h> #import <UIKit/UIKit.h> #import "base/mac/foundation_util.h" @@ -27,15 +28,38 @@ // hash changed, the pasteboard content is considered to have changed. NSString* const kPasteboardEntryMD5Key = @"PasteboardEntryMD5"; -// Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|. -// This value is used to detect pasteboard content change. Keeping only 4 bytes -// is a privacy requirement to introduce collision and allow deniability of -// having copied a given string. -NSData* WeakMD5FromNSString(NSString* string) { +// Compute a hash consisting of the first 4 bytes of the MD5 hash of |string|, +// |image_data|, and |url|. This value is used to detect pasteboard content +// change. Keeping only 4 bytes is a privacy requirement to introduce collision +// and allow deniability of having copied a given string, image, or url. +// +// |image_data| is passed in as NSData instead of UIImage because converting +// UIImage to NSData can be slow for large images and getting NSData directly +// from the pasteboard is quicker. +NSData* WeakMD5FromPasteboardData(NSString* string, + NSData* image_data, + NSURL* url) { + CC_MD5_CTX ctx; + CC_MD5_Init(&ctx); + + const std::string clipboard_string = base::SysNSStringToUTF8(string); + const char* c_string = clipboard_string.c_str(); + CC_MD5_Update(&ctx, c_string, strlen(c_string)); + + // This hash is used only to tell if the image has changed, so + // limit the number of bytes to hash to prevent slowdown. + NSUInteger bytes_to_hash = fmin([image_data length], 1000000); + if (bytes_to_hash > 0) { + CC_MD5_Update(&ctx, [image_data bytes], bytes_to_hash); + } + + const std::string url_string = base::SysNSStringToUTF8([url absoluteString]); + const char* url_c_string = url_string.c_str(); + CC_MD5_Update(&ctx, url_c_string, strlen(url_c_string)); + unsigned char hash[CC_MD5_DIGEST_LENGTH]; - const std::string clipboard = base::SysNSStringToUTF8(string); - const char* c_string = clipboard.c_str(); - CC_MD5(c_string, strlen(c_string), hash); + CC_MD5_Final(hash, &ctx); + NSData* data = [NSData dataWithBytes:hash length:4]; return data; } @@ -124,7 +148,11 @@ - (NSData*)getCurrentMD5 { NSString* pasteboardString = [UIPasteboard generalPasteboard].string; - NSData* md5 = WeakMD5FromNSString(pasteboardString); + NSData* pasteboardImageData = [[UIPasteboard generalPasteboard] + dataForPasteboardType:(NSString*)kUTTypeImage]; + NSURL* pasteboardURL = [UIPasteboard generalPasteboard].URL; + NSData* md5 = WeakMD5FromPasteboardData(pasteboardString, pasteboardImageData, + pasteboardURL); return md5; } @@ -166,6 +194,14 @@ return [UIPasteboard generalPasteboard].string; } +- (UIImage*)recentImageFromClipboard { + [self updateIfNeeded]; + if ([self clipboardContentAge] > self.maximumAgeOfClipboard) { + return nil; + } + return [UIPasteboard generalPasteboard].image; +} + - (NSTimeInterval)clipboardContentAge { return -[self.lastPasteboardChangeDate timeIntervalSinceNow]; }
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.h b/components/open_from_clipboard/clipboard_recent_content_ios.h index dadc619..ceb4d41 100644 --- a/components/open_from_clipboard/clipboard_recent_content_ios.h +++ b/components/open_from_clipboard/clipboard_recent_content_ios.h
@@ -40,6 +40,7 @@ // ClipboardRecentContent implementation. base::Optional<GURL> GetRecentURLFromClipboard() override; base::Optional<base::string16> GetRecentTextFromClipboard() override; + base::Optional<gfx::Image> GetRecentImageFromClipboard() override; base::TimeDelta GetClipboardContentAge() const override; void SuppressClipboardContent() override;
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios.mm b/components/open_from_clipboard/clipboard_recent_content_ios.mm index ac6d132..28273e6 100644 --- a/components/open_from_clipboard/clipboard_recent_content_ios.mm +++ b/components/open_from_clipboard/clipboard_recent_content_ios.mm
@@ -89,6 +89,16 @@ return base::SysNSStringToUTF16(text_from_pasteboard); } +base::Optional<gfx::Image> +ClipboardRecentContentIOS::GetRecentImageFromClipboard() { + UIImage* image_from_pasteboard = [implementation_ recentImageFromClipboard]; + if (!image_from_pasteboard) { + return base::nullopt; + } + + return gfx::Image(image_from_pasteboard); +} + ClipboardRecentContentIOS::~ClipboardRecentContentIOS() {} base::TimeDelta ClipboardRecentContentIOS::GetClipboardContentAge() const {
diff --git a/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm b/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm index d11f6a9..96742db 100644 --- a/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm +++ b/components/open_from_clipboard/clipboard_recent_content_ios_unittest.mm
@@ -17,12 +17,12 @@ namespace { -UIImage* TestUIImage() { +UIImage* TestUIImage(UIColor* color = [UIColor redColor]) { CGRect frame = CGRectMake(0, 0, 1.0, 1.0); UIGraphicsBeginImageContext(frame.size); CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [UIColor redColor].CGColor); + CGContextSetFillColorWithColor(context, color.CGColor); CGContextFillRect(context, frame); UIImage* image = UIGraphicsGetImageFromCurrentImageContext(); @@ -156,6 +156,11 @@ void VerifyClipboardTextDoesNotExist() { EXPECT_FALSE(clipboard_content_->GetRecentTextFromClipboard().has_value()); } + + void VerifyIfClipboardImageExists(bool exists) { + EXPECT_EQ(clipboard_content_->GetRecentImageFromClipboard().has_value(), + exists); + } }; TEST_F(ClipboardRecentContentIOSTest, SchemeFiltering) { @@ -205,7 +210,9 @@ VerifyClipboardTextDoesNotExist(); } -TEST_F(ClipboardRecentContentIOSTest, SupressedPasteboard) { +// Checks that if the user suppresses content, no text will be returned, +// and if the text changes, the new text will be returned again. +TEST_F(ClipboardRecentContentIOSTest, SupressedPasteboardText) { SetPasteboardContent(kRecognizedURL); // Test that recent pasteboard data is provided. @@ -240,6 +247,38 @@ VerifyClipboardTextExists(kRecognizedURL2); } +// Checks that if the user suppresses content, no image will be returned, +// and if the image changes, the new image will be returned again. +TEST_F(ClipboardRecentContentIOSTest, SupressedPasteboardImage) { + SetPasteboardImage(TestUIImage()); + + // Test that recent pasteboard data is provided. + VerifyIfClipboardImageExists(true); + + // Suppress the content of the pasteboard. + clipboard_content_->SuppressClipboardContent(); + + // Check that the pasteboard content is suppressed. + VerifyIfClipboardImageExists(false); + + // Create a new clipboard content to test persistence. + ResetClipboardRecentContent(kAppSpecificScheme, + base::TimeDelta::FromDays(10)); + + // Check that the pasteboard content is still suppressed. + VerifyIfClipboardImageExists(false); + + // Check that even if the device is restarted, pasteboard content is + // still suppressed. + SimulateDeviceRestart(); + VerifyIfClipboardImageExists(false); + + // Check that if the pasteboard changes, the new content is not + // supressed anymore. + SetPasteboardImage(TestUIImage([UIColor greenColor])); + VerifyIfClipboardImageExists(true); +} + // Checks that if user copies something other than a string we don't cache the // string in pasteboard. TEST_F(ClipboardRecentContentIOSTest, AddingNonStringRemovesCachedString) { @@ -248,6 +287,8 @@ // Test that recent pasteboard data is provided as text and url. VerifyClipboardURLExists(kRecognizedURL); VerifyClipboardTextExists(kRecognizedURL); + // Image pasteboard should be empty + VerifyIfClipboardImageExists(false); // Overwrite pasteboard with an image. SetPasteboardImage(TestUIImage()); @@ -255,9 +296,13 @@ // Url and text pasteboard should appear empty. VerifyClipboardURLDoesNotExist(); VerifyClipboardTextDoesNotExist(); + // Image pasteboard should be full + VerifyIfClipboardImageExists(true); // Tests that if URL is added again, pasteboard provides it normally. SetPasteboardContent(kRecognizedURL); VerifyClipboardURLExists(kRecognizedURL); VerifyClipboardTextExists(kRecognizedURL); + // Image pasteboard should be empty + VerifyIfClipboardImageExists(false); }
diff --git a/components/open_from_clipboard/fake_clipboard_recent_content.cc b/components/open_from_clipboard/fake_clipboard_recent_content.cc index 7a531ce4..f957c3d 100644 --- a/components/open_from_clipboard/fake_clipboard_recent_content.cc +++ b/components/open_from_clipboard/fake_clipboard_recent_content.cc
@@ -24,6 +24,14 @@ return clipboard_text_content_; } +base::Optional<gfx::Image> +FakeClipboardRecentContent::GetRecentImageFromClipboard() { + if (suppress_content_) + return base::nullopt; + + return clipboard_image_content_; +} + base::TimeDelta FakeClipboardRecentContent::GetClipboardContentAge() const { return content_age_; } @@ -37,6 +45,7 @@ DCHECK(url.is_valid()); clipboard_url_content_ = url; clipboard_text_content_ = base::nullopt; + clipboard_image_content_ = base::nullopt; content_age_ = content_age; suppress_content_ = false; } @@ -45,6 +54,17 @@ base::TimeDelta content_age) { clipboard_url_content_ = base::nullopt; clipboard_text_content_ = text; + clipboard_image_content_ = base::nullopt; + content_age_ = content_age; + suppress_content_ = false; +} + +void FakeClipboardRecentContent::SetClipboardImage( + const gfx::Image& image, + base::TimeDelta content_age) { + clipboard_url_content_ = base::nullopt; + clipboard_text_content_ = base::nullopt; + clipboard_image_content_ = image; content_age_ = content_age; suppress_content_ = false; }
diff --git a/components/open_from_clipboard/fake_clipboard_recent_content.h b/components/open_from_clipboard/fake_clipboard_recent_content.h index c1170dc..61798399 100644 --- a/components/open_from_clipboard/fake_clipboard_recent_content.h +++ b/components/open_from_clipboard/fake_clipboard_recent_content.h
@@ -8,6 +8,7 @@ #include "base/macros.h" #include "base/time/time.h" #include "components/open_from_clipboard/clipboard_recent_content.h" +#include "ui/gfx/image/image.h" #include "url/gurl.h" // FakeClipboardRecentContent implements ClipboardRecentContent interface by @@ -20,18 +21,22 @@ // ClipboardRecentContent implementation. base::Optional<GURL> GetRecentURLFromClipboard() override; base::Optional<base::string16> GetRecentTextFromClipboard() override; + base::Optional<gfx::Image> GetRecentImageFromClipboard() override; base::TimeDelta GetClipboardContentAge() const override; void SuppressClipboardContent() override; - // Sets the URL and clipboard content age. This clears the text + // Sets the URL and clipboard content age. This clears the text and image. void SetClipboardURL(const GURL& url, base::TimeDelta content_age); - // Sets the text and clipboard content age. This clears the url. + // Sets the text and clipboard content age. This clears the URL and image. void SetClipboardText(const base::string16& text, base::TimeDelta content_age); + // Sets the image and clipboard content age. This clears the URL and text. + void SetClipboardImage(const gfx::Image& image, base::TimeDelta content_age); private: base::Optional<GURL> clipboard_url_content_; base::Optional<base::string16> clipboard_text_content_; + base::Optional<gfx::Image> clipboard_image_content_; base::TimeDelta content_age_; bool suppress_content_;
diff --git a/components/password_manager/content/browser/bad_message.cc b/components/password_manager/content/browser/bad_message.cc index b59280fa..8f7ad688 100644 --- a/components/password_manager/content/browser/bad_message.cc +++ b/components/password_manager/content/browser/bad_message.cc
@@ -64,9 +64,7 @@ return CheckChildProcessSecurityPolicyForURL(frame, password_form.origin, reason) && CheckChildProcessSecurityPolicyForURL( - frame, GURL(password_form.signon_realm), reason) && - CheckChildProcessSecurityPolicyForURL( - frame, password_form.form_data.origin, reason); + frame, GURL(password_form.signon_realm), reason); } bool CheckChildProcessSecurityPolicy(
diff --git a/components/printing/browser/BUILD.gn b/components/printing/browser/BUILD.gn index 4857697..9e4b076d 100644 --- a/components/printing/browser/BUILD.gn +++ b/components/printing/browser/BUILD.gn
@@ -12,6 +12,8 @@ "print_manager.h", "print_manager_utils.cc", "print_manager_utils.h", + "printer_capabilities.cc", + "printer_capabilities.h", ] public_deps = [ @@ -20,10 +22,40 @@ deps = [ "//base", + "//components/crash/core/common", "//components/printing/common", "//components/services/pdf_compositor/public/interfaces", + "//components/strings:components_strings_grit", "//printing", "//printing/common:common", "//services/service_manager/public/cpp", + "//ui/base", + "//ui/gfx/geometry", ] + + if (is_mac) { + sources += [ + "printer_capabilities_mac.h", + "printer_capabilities_mac.mm", + ] + } +} + +source_set("unit_tests") { + testonly = true + sources = [ + "printer_capabilities_unittest.cc", + ] + + deps = [ + "//base", + "//components/printing/browser", + "//content/test:test_support", + "//printing:test_support", + "//testing/gtest", + ] + + if (is_mac) { + sources += [ "printer_capabilities_mac_unittest.mm" ] + } }
diff --git a/components/printing/browser/DEPS b/components/printing/browser/DEPS index 9adac87..a24bd0d5ad 100644 --- a/components/printing/browser/DEPS +++ b/components/printing/browser/DEPS
@@ -1,7 +1,16 @@ include_rules = [ + "+components/crash/core/common", "+components/services/pdf_compositor/public/cpp", "+components/services/pdf_compositor/public/interfaces", + "+components/strings/grit", "+content/public/browser", "+mojo/public/cpp/system", "+services/service_manager/public/cpp", + "+ui/base/l10n", ] + +specific_include_rules = { + "printer_capabilities_unittest.cc": [ + "+content/public/test", + ], +}
diff --git a/components/printing/common/printer_capabilities.cc b/components/printing/browser/printer_capabilities.cc similarity index 98% rename from components/printing/common/printer_capabilities.cc rename to components/printing/browser/printer_capabilities.cc index 018578b..382db0a 100644 --- a/components/printing/common/printer_capabilities.cc +++ b/components/printing/browser/printer_capabilities.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/printing/common/printer_capabilities.h" +#include "components/printing/browser/printer_capabilities.h" #include <memory> #include <string>
diff --git a/components/printing/common/printer_capabilities.h b/components/printing/browser/printer_capabilities.h similarity index 87% rename from components/printing/common/printer_capabilities.h rename to components/printing/browser/printer_capabilities.h index d02e65f6..698af12 100644 --- a/components/printing/common/printer_capabilities.h +++ b/components/printing/browser/printer_capabilities.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_PRINTING_COMMON_PRINTER_CAPABILITIES_H_ -#define COMPONENTS_PRINTING_COMMON_PRINTER_CAPABILITIES_H_ +#ifndef COMPONENTS_PRINTING_BROWSER_PRINTER_CAPABILITIES_H_ +#define COMPONENTS_PRINTING_BROWSER_PRINTER_CAPABILITIES_H_ #include <memory> #include <string> @@ -39,4 +39,4 @@ } // namespace printing -#endif // COMPONENTS_PRINTING_COMMON_PRINTER_CAPABILITIES_H_ +#endif // COMPONENTS_PRINTING_BROWSER_PRINTER_CAPABILITIES_H_
diff --git a/components/printing/common/printer_capabilities_mac.h b/components/printing/browser/printer_capabilities_mac.h similarity index 74% rename from components/printing/common/printer_capabilities_mac.h rename to components/printing/browser/printer_capabilities_mac.h index e391bfc..eb37014 100644 --- a/components/printing/common/printer_capabilities_mac.h +++ b/components/printing/browser/printer_capabilities_mac.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_PRINTING_COMMON_PRINTER_CAPABILITIES_MAC_H_ -#define COMPONENTS_PRINTING_COMMON_PRINTER_CAPABILITIES_MAC_H_ +#ifndef COMPONENTS_PRINTING_BROWSER_PRINTER_CAPABILITIES_MAC_H_ +#define COMPONENTS_PRINTING_BROWSER_PRINTER_CAPABILITIES_MAC_H_ #include "printing/backend/print_backend.h" @@ -25,4 +25,4 @@ } // namespace printing -#endif // COMPONENTS_PRINTING_COMMON_PRINTER_CAPABILITIES_MAC_H_ +#endif // COMPONENTS_PRINTING_BROWSER_PRINTER_CAPABILITIES_MAC_H_
diff --git a/components/printing/common/printer_capabilities_mac.mm b/components/printing/browser/printer_capabilities_mac.mm similarity index 97% rename from components/printing/common/printer_capabilities_mac.mm rename to components/printing/browser/printer_capabilities_mac.mm index 2dc3429..3d790c3 100644 --- a/components/printing/common/printer_capabilities_mac.mm +++ b/components/printing/browser/printer_capabilities_mac.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/printing/common/printer_capabilities_mac.h" +#include "components/printing/browser/printer_capabilities_mac.h" #import <AppKit/AppKit.h>
diff --git a/components/printing/common/printer_capabilities_mac_unittest.mm b/components/printing/browser/printer_capabilities_mac_unittest.mm similarity index 98% rename from components/printing/common/printer_capabilities_mac_unittest.mm rename to components/printing/browser/printer_capabilities_mac_unittest.mm index af020f30..5dfd716d 100644 --- a/components/printing/common/printer_capabilities_mac_unittest.mm +++ b/components/printing/browser/printer_capabilities_mac_unittest.mm
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/printing/common/printer_capabilities_mac.h" +#include "components/printing/browser/printer_capabilities_mac.h" #include "base/files/scoped_temp_dir.h" #include "base/mac/foundation_util.h"
diff --git a/components/printing/common/printer_capabilities_unittest.cc b/components/printing/browser/printer_capabilities_unittest.cc similarity index 98% rename from components/printing/common/printer_capabilities_unittest.cc rename to components/printing/browser/printer_capabilities_unittest.cc index 931d275..ec5b23a 100644 --- a/components/printing/common/printer_capabilities_unittest.cc +++ b/components/printing/browser/printer_capabilities_unittest.cc
@@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "components/printing/browser/printer_capabilities.h" + #include <memory> #include "base/bind.h" #include "base/memory/ref_counted.h" #include "base/stl_util.h" #include "base/values.h" -#include "components/printing/common/printer_capabilities.h" #include "content/public/test/test_browser_thread_bundle.h" #include "printing/backend/test_print_backend.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/printing/common/BUILD.gn b/components/printing/common/BUILD.gn index f0dbe71..40da037 100644 --- a/components/printing/common/BUILD.gn +++ b/components/printing/common/BUILD.gn
@@ -8,51 +8,19 @@ "cloud_print_cdd_conversion.h", "print_messages.cc", "print_messages.h", - "printer_capabilities.cc", - "printer_capabilities.h", "printing_param_traits_macros.h", ] deps = [ "//base", "//components/cloud_devices/common:common", - "//components/crash/core/common", - "//components/strings:components_strings_grit", "//ipc", "//printing", "//printing/common:common", "//third_party/blink/public:blink_headers", - "//ui/base", - "//ui/gfx", "//ui/gfx/geometry", "//ui/gfx/ipc", "//ui/gfx/ipc/geometry", "//ui/gfx/ipc/skia", ] - - if (is_mac) { - sources += [ - "printer_capabilities_mac.h", - "printer_capabilities_mac.mm", - ] - } -} - -source_set("unit_tests") { - testonly = true - sources = [ - "printer_capabilities_unittest.cc", - ] - - deps = [ - ":common", - "//base", - "//content/test:test_support", - "//printing:test_support", - "//testing/gtest", - ] - - if (is_mac) { - sources += [ "printer_capabilities_mac_unittest.mm" ] - } }
diff --git a/components/printing/common/DEPS b/components/printing/common/DEPS deleted file mode 100644 index 245e3ade..0000000 --- a/components/printing/common/DEPS +++ /dev/null
@@ -1,11 +0,0 @@ -include_rules = [ - "+components/crash/core/common", - "+components/strings/grit", - "+ui/base/l10n", -] - -specific_include_rules = { - "printer_capabilities_unittest.cc": [ - "+content/public/test", - ], -}
diff --git a/components/safe_browsing/android/DEPS b/components/safe_browsing/android/DEPS index 1640ef3..f56bb485 100644 --- a/components/safe_browsing/android/DEPS +++ b/components/safe_browsing/android/DEPS
@@ -2,4 +2,4 @@ "+components/variations", "+content/public/test", "+jni", -] \ No newline at end of file +]
diff --git a/components/safe_browsing/browser/threat_details.cc b/components/safe_browsing/browser/threat_details.cc index 3dca6dc..85f7a04 100644 --- a/components/safe_browsing/browser/threat_details.cc +++ b/components/safe_browsing/browser/threat_details.cc
@@ -101,8 +101,19 @@ return ClientSafeBrowsingReportRequest::URL_SUSPICIOUS; case SB_THREAT_TYPE_BILLING: return ClientSafeBrowsingReportRequest::BILLING; - default: // Gated by SafeBrowsingBlockingPage::ShouldReportThreatDetails. - NOTREACHED() << "We should not send report for threat type " + case SB_THREAT_TYPE_APK_DOWNLOAD: + return ClientSafeBrowsingReportRequest::APK_DOWNLOAD; + case SB_THREAT_TYPE_UNUSED: + case SB_THREAT_TYPE_SAFE: + case SB_THREAT_TYPE_URL_BINARY_MALWARE: + case SB_THREAT_TYPE_EXTENSION: + case SB_THREAT_TYPE_BLACKLISTED_RESOURCE: + case SB_THREAT_TYPE_API_ABUSE: + case SB_THREAT_TYPE_SUBRESOURCE_FILTER: + case SB_THREAT_TYPE_CSD_WHITELIST: + case DEPRECATED_SB_THREAT_TYPE_URL_PASSWORD_PROTECTION_PHISHING: + // Gated by SafeBrowsingBlockingPage::ShouldReportThreatDetails. + NOTREACHED() << "We should not send report for threat type: " << threat_type; return ClientSafeBrowsingReportRequest::UNKNOWN; } @@ -832,7 +843,8 @@ return; if (!report_ || - report_->type() != ClientSafeBrowsingReportRequest::URL_SUSPICIOUS) { + (report_->type() != ClientSafeBrowsingReportRequest::URL_SUSPICIOUS && + report_->type() != ClientSafeBrowsingReportRequest::APK_DOWNLOAD)) { return; }
diff --git a/components/safe_browsing/db/v4_protocol_manager_util.h b/components/safe_browsing/db/v4_protocol_manager_util.h index 54dbb8e..d2b74ad 100644 --- a/components/safe_browsing/db/v4_protocol_manager_util.h +++ b/components/safe_browsing/db/v4_protocol_manager_util.h
@@ -151,11 +151,14 @@ // The page loaded a resource from the Suspicious Site list. SB_THREAT_TYPE_SUSPICIOUS_SITE, - // Enterprise password reuse detected on low reputation page, + // Enterprise password reuse detected on low reputation page. SB_THREAT_TYPE_ENTERPRISE_PASSWORD_REUSE, // Potential billing detected. SB_THREAT_TYPE_BILLING, + + // Off-market APK file downloaded, which could be potentially dangerous. + SB_THREAT_TYPE_APK_DOWNLOAD, }; using SBThreatTypeSet = base::flat_set<SBThreatType>;
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc index bdf60837..acb3525 100644 --- a/components/safe_browsing/features.cc +++ b/components/safe_browsing/features.cc
@@ -45,6 +45,9 @@ const base::Feature kSuspiciousSiteTriggerQuotaFeature{ "SafeBrowsingSuspiciousSiteTriggerQuota", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kTelemetryForApkDownloads{ + "SafeBrowsingTelemetryForApkDownloads", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kThreatDomDetailsTagAndAttributeFeature{ "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT}; @@ -73,6 +76,7 @@ {&kCommittedSBInterstitials, true}, {&kForceEnableResetPasswordWebUI, true}, {&kSuspiciousSiteTriggerQuotaFeature, true}, + {&kTelemetryForApkDownloads, true}, {&kThreatDomDetailsTagAndAttributeFeature, false}, {&kTriggerThrottlerDailyQuotaFeature, false}, {&kUseLocalBlacklistsV2, true},
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h index ac5cd1c..2e177b6 100644 --- a/components/safe_browsing/features.h +++ b/components/safe_browsing/features.h
@@ -37,6 +37,10 @@ // Controls the daily quota for the suspicious site trigger. extern const base::Feature kSuspiciousSiteTriggerQuotaFeature; +// Controls whether we collect and send the referrer chain and other information +// for APK downloads on Android. +extern const base::Feature kTelemetryForApkDownloads; + // Specifies which non-resource HTML Elements to collect based on their tag and // attributes. It's a single param containing a comma-separated list of pairs. // For example: "tag1,id,tag1,height,tag2,foo" - this will collect elements with
diff --git a/components/safe_browsing/proto/csd.proto b/components/safe_browsing/proto/csd.proto index a7f657a..6a8ed9a 100644 --- a/components/safe_browsing/proto/csd.proto +++ b/components/safe_browsing/proto/csd.proto
@@ -1064,6 +1064,7 @@ AD_SAMPLE = 14; URL_SUSPICIOUS = 15; BILLING = 16; + APK_DOWNLOAD = 17; } message HTTPHeader {
diff --git a/components/safe_browsing/triggers/trigger_manager.cc b/components/safe_browsing/triggers/trigger_manager.cc index 8884318f..b6a088d 100644 --- a/components/safe_browsing/triggers/trigger_manager.cc +++ b/components/safe_browsing/triggers/trigger_manager.cc
@@ -38,6 +38,10 @@ // Suspicious site collection happens in the background so the user must // already be opted in before the trigger is allowed to run. return true; + case TriggerType::APK_DOWNLOAD: + // APK download collection happens in the background so the user must + // already be opted in before the trigger is allowed to run. + return true; } // By default, require opt-in for all triggers. return true;
diff --git a/components/safe_browsing/triggers/trigger_throttler.cc b/components/safe_browsing/triggers/trigger_throttler.cc index 4d7de8d..49458e3 100644 --- a/components/safe_browsing/triggers/trigger_throttler.cc +++ b/components/safe_browsing/triggers/trigger_throttler.cc
@@ -245,6 +245,7 @@ switch (trigger_type) { case TriggerType::SECURITY_INTERSTITIAL: case TriggerType::GAIA_PASSWORD_REUSE: + case TriggerType::APK_DOWNLOAD: return kUnlimitedTriggerQuota; case TriggerType::AD_SAMPLE: // Ad Samples have a non-zero default quota, but it can be overwritten
diff --git a/components/safe_browsing/triggers/trigger_throttler.h b/components/safe_browsing/triggers/trigger_throttler.h index dc0c816d..321fc8b5 100644 --- a/components/safe_browsing/triggers/trigger_throttler.h +++ b/components/safe_browsing/triggers/trigger_throttler.h
@@ -39,8 +39,9 @@ AD_SAMPLE = 2, GAIA_PASSWORD_REUSE = 3, SUSPICIOUS_SITE = 4, + APK_DOWNLOAD = 5, kMinTriggerType = SECURITY_INTERSTITIAL, - kMaxTriggerType = SUSPICIOUS_SITE, + kMaxTriggerType = APK_DOWNLOAD, }; struct TriggerTypeHash {
diff --git a/components/ui_devtools/viz_views/BUILD.gn b/components/ui_devtools/viz/BUILD.gn similarity index 94% rename from components/ui_devtools/viz_views/BUILD.gn rename to components/ui_devtools/viz/BUILD.gn index e58f3ff..235b1d6a 100644 --- a/components/ui_devtools/viz_views/BUILD.gn +++ b/components/ui_devtools/viz/BUILD.gn
@@ -4,7 +4,7 @@ import("//components/viz/viz.gni") -source_set("viz_views") { +source_set("viz") { sources = [ "dom_agent_viz.cc", "dom_agent_viz.h", @@ -30,7 +30,7 @@ ] deps = [ - ":viz_views", + ":viz", "//components/ui_devtools", "//components/ui_devtools:test_support", "//components/viz/service",
diff --git a/components/ui_devtools/viz_views/DEPS b/components/ui_devtools/viz/DEPS similarity index 100% rename from components/ui_devtools/viz_views/DEPS rename to components/ui_devtools/viz/DEPS
diff --git a/components/ui_devtools/viz/OWNERS b/components/ui_devtools/viz/OWNERS new file mode 100644 index 0000000..65aaa31 --- /dev/null +++ b/components/ui_devtools/viz/OWNERS
@@ -0,0 +1 @@ +kylechar@chromium.org
diff --git a/components/ui_devtools/viz_views/dom_agent_viz.cc b/components/ui_devtools/viz/dom_agent_viz.cc similarity index 98% rename from components/ui_devtools/viz_views/dom_agent_viz.cc rename to components/ui_devtools/viz/dom_agent_viz.cc index 4a5c59a94..7605220 100644 --- a/components/ui_devtools/viz_views/dom_agent_viz.cc +++ b/components/ui_devtools/viz/dom_agent_viz.cc
@@ -2,13 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/ui_devtools/viz_views/dom_agent_viz.h" +#include "components/ui_devtools/viz/dom_agent_viz.h" #include "base/stl_util.h" #include "components/ui_devtools/root_element.h" #include "components/ui_devtools/ui_element.h" -#include "components/ui_devtools/viz_views/frame_sink_element.h" -#include "components/ui_devtools/viz_views/surface_element.h" +#include "components/ui_devtools/viz/frame_sink_element.h" +#include "components/ui_devtools/viz/surface_element.h" #include "components/viz/common/frame_sinks/begin_frame_args.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/surface_id.h"
diff --git a/components/ui_devtools/viz_views/dom_agent_viz.h b/components/ui_devtools/viz/dom_agent_viz.h similarity index 96% rename from components/ui_devtools/viz_views/dom_agent_viz.h rename to components/ui_devtools/viz/dom_agent_viz.h index 8cf00b16..d5618f80 100644 --- a/components/ui_devtools/viz_views/dom_agent_viz.h +++ b/components/ui_devtools/viz/dom_agent_viz.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_DOM_AGENT_VIZ_H_ -#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_DOM_AGENT_VIZ_H_ +#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_DOM_AGENT_VIZ_H_ +#define COMPONENTS_UI_DEVTOOLS_VIZ_DOM_AGENT_VIZ_H_ #include "base/containers/flat_map.h" #include "base/containers/flat_set.h" @@ -20,7 +20,7 @@ class SurfaceId; class SurfaceInfo; class SurfaceManager; -} +} // namespace viz namespace ui_devtools { class FrameSinkElement; @@ -141,4 +141,4 @@ } // namespace ui_devtools -#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_DOM_AGENT_VIZ_H_ +#endif // COMPONENTS_UI_DEVTOOLS_VIZ_DOM_AGENT_VIZ_H_
diff --git a/components/ui_devtools/viz_views/frame_sink_element.cc b/components/ui_devtools/viz/frame_sink_element.cc similarity index 98% rename from components/ui_devtools/viz_views/frame_sink_element.cc rename to components/ui_devtools/viz/frame_sink_element.cc index 6b75b3da0..697ded6a 100644 --- a/components/ui_devtools/viz_views/frame_sink_element.cc +++ b/components/ui_devtools/viz/frame_sink_element.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/ui_devtools/viz_views/frame_sink_element.h" +#include "components/ui_devtools/viz/frame_sink_element.h" #include "base/strings/string_piece.h" #include "components/ui_devtools/Protocol.h"
diff --git a/components/ui_devtools/viz_views/frame_sink_element.h b/components/ui_devtools/viz/frame_sink_element.h similarity index 91% rename from components/ui_devtools/viz_views/frame_sink_element.h rename to components/ui_devtools/viz/frame_sink_element.h index 76a52f0..70dc5235c 100644 --- a/components/ui_devtools/viz_views/frame_sink_element.h +++ b/components/ui_devtools/viz/frame_sink_element.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_FRAME_SINK_ELEMENT_H_ -#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_FRAME_SINK_ELEMENT_H_ +#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_FRAME_SINK_ELEMENT_H_ +#define COMPONENTS_UI_DEVTOOLS_VIZ_FRAME_SINK_ELEMENT_H_ #include "base/macros.h" #include "components/ui_devtools/ui_element.h" @@ -64,4 +64,4 @@ } // namespace ui_devtools -#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_FRAME_SINK_ELEMENT_H_ +#endif // COMPONENTS_UI_DEVTOOLS_VIZ_FRAME_SINK_ELEMENT_H_
diff --git a/components/ui_devtools/viz_views/overlay_agent_viz.cc b/components/ui_devtools/viz/overlay_agent_viz.cc similarity index 92% rename from components/ui_devtools/viz_views/overlay_agent_viz.cc rename to components/ui_devtools/viz/overlay_agent_viz.cc index 058db6cf..7501924 100644 --- a/components/ui_devtools/viz_views/overlay_agent_viz.cc +++ b/components/ui_devtools/viz/overlay_agent_viz.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/ui_devtools/viz_views/overlay_agent_viz.h" +#include "components/ui_devtools/viz/overlay_agent_viz.h" namespace ui_devtools {
diff --git a/components/ui_devtools/viz_views/overlay_agent_viz.h b/components/ui_devtools/viz/overlay_agent_viz.h similarity index 78% rename from components/ui_devtools/viz_views/overlay_agent_viz.h rename to components/ui_devtools/viz/overlay_agent_viz.h index ef4dcdcc..c71652c6 100644 --- a/components/ui_devtools/viz_views/overlay_agent_viz.h +++ b/components/ui_devtools/viz/overlay_agent_viz.h
@@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_OVERLAY_AGENT_VIZ_H_ -#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_OVERLAY_AGENT_VIZ_H_ +#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_OVERLAY_AGENT_VIZ_H_ +#define COMPONENTS_UI_DEVTOOLS_VIZ_OVERLAY_AGENT_VIZ_H_ #include "components/ui_devtools/Overlay.h" #include "components/ui_devtools/overlay_agent.h" -#include "components/ui_devtools/viz_views/dom_agent_viz.h" +#include "components/ui_devtools/viz/dom_agent_viz.h" namespace ui_devtools { @@ -32,4 +32,4 @@ } // namespace ui_devtools -#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_OVERLAY_AGENT_VIZ_H_ +#endif // COMPONENTS_UI_DEVTOOLS_VIZ_OVERLAY_AGENT_VIZ_H_
diff --git a/components/ui_devtools/viz_views/surface_element.cc b/components/ui_devtools/viz/surface_element.cc similarity index 97% rename from components/ui_devtools/viz_views/surface_element.cc rename to components/ui_devtools/viz/surface_element.cc index 56ac892..9c46fa9 100644 --- a/components/ui_devtools/viz_views/surface_element.cc +++ b/components/ui_devtools/viz/surface_element.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/ui_devtools/viz_views/surface_element.h" +#include "components/ui_devtools/viz/surface_element.h" #include "components/ui_devtools/Protocol.h" #include "components/ui_devtools/ui_element_delegate.h"
diff --git a/components/ui_devtools/viz_views/surface_element.h b/components/ui_devtools/viz/surface_element.h similarity index 88% rename from components/ui_devtools/viz_views/surface_element.h rename to components/ui_devtools/viz/surface_element.h index 71b75c2d..eed60c7 100644 --- a/components/ui_devtools/viz_views/surface_element.h +++ b/components/ui_devtools/viz/surface_element.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_SURFACE_ELEMENT_H_ -#define COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_SURFACE_ELEMENT_H_ +#ifndef COMPONENTS_UI_DEVTOOLS_VIZ_SURFACE_ELEMENT_H_ +#define COMPONENTS_UI_DEVTOOLS_VIZ_SURFACE_ELEMENT_H_ #include "base/macros.h" #include "components/ui_devtools/ui_element.h" @@ -47,4 +47,4 @@ } // namespace ui_devtools -#endif // COMPONENTS_UI_DEVTOOLS_VIZ_VIEWS_SURFACE_ELEMENT_H_ +#endif // COMPONENTS_UI_DEVTOOLS_VIZ_SURFACE_ELEMENT_H_
diff --git a/components/ui_devtools/viz_views/viz_devtools_unittest.cc b/components/ui_devtools/viz/viz_devtools_unittest.cc similarity index 98% rename from components/ui_devtools/viz_views/viz_devtools_unittest.cc rename to components/ui_devtools/viz/viz_devtools_unittest.cc index c51e7777..849168f2 100644 --- a/components/ui_devtools/viz_views/viz_devtools_unittest.cc +++ b/components/ui_devtools/viz/viz_devtools_unittest.cc
@@ -5,10 +5,10 @@ #include "components/ui_devtools/css_agent.h" #include "components/ui_devtools/ui_devtools_unittest_utils.h" #include "components/ui_devtools/ui_element.h" -#include "components/ui_devtools/viz_views/dom_agent_viz.h" -#include "components/ui_devtools/viz_views/frame_sink_element.h" -#include "components/ui_devtools/viz_views/overlay_agent_viz.h" -#include "components/ui_devtools/viz_views/surface_element.h" +#include "components/ui_devtools/viz/dom_agent_viz.h" +#include "components/ui_devtools/viz/frame_sink_element.h" +#include "components/ui_devtools/viz/overlay_agent_viz.h" +#include "components/ui_devtools/viz/surface_element.h" #include "components/viz/common/surfaces/frame_sink_id.h" #include "components/viz/common/surfaces/surface_id.h" #include "components/viz/common/surfaces/surface_info.h"
diff --git a/components/url_formatter/top_domains/BUILD.gn b/components/url_formatter/top_domains/BUILD.gn index 4abbbec0..5edcf0d5 100644 --- a/components/url_formatter/top_domains/BUILD.gn +++ b/components/url_formatter/top_domains/BUILD.gn
@@ -93,6 +93,17 @@ ] } +source_set("unit_tests") { + testonly = true + sources = [ + "top_domain_util_unittest.cc", + ] + deps = [ + ":common", + "//testing/gtest", + ] +} + # TODO(crbug/915921): Combine this and the previous one into a # compiled_action_foreach target. compiled_action("generate_top_domains_for_edit_distance") {
diff --git a/components/url_formatter/top_domains/top_domain_util.cc b/components/url_formatter/top_domains/top_domain_util.cc index e1099e7..68c74018 100644 --- a/components/url_formatter/top_domains/top_domain_util.cc +++ b/components/url_formatter/top_domains/top_domain_util.cc
@@ -15,26 +15,21 @@ // comparison. Shorter domains are ignored. const size_t kMinLengthForEditDistance = 5u; -// Returns the portion of hostname without the registry part. -// E.g. For hostname = "google.com", the registry is "com", and the return value -// will be 6 (length of "google"). -size_t GetWithoutRegistryLength(const std::string& hostname) { +} // namespace + +std::string HostnameWithoutRegistry(const std::string& hostname) { + DCHECK(!hostname.empty()); const size_t registry_size = net::registry_controlled_domains::PermissiveGetHostRegistryLength( hostname.c_str(), net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES); - if (registry_size == 0) { - return hostname.size(); - } - DCHECK_LE(registry_size, hostname.size() - 1); - return hostname.size() - registry_size - 1; + return hostname.substr(0, hostname.size() - registry_size); } -} // namespace - bool IsEditDistanceCandidate(const std::string& hostname) { - return GetWithoutRegistryLength(hostname) >= kMinLengthForEditDistance; + return !hostname.empty() && + HostnameWithoutRegistry(hostname).size() >= kMinLengthForEditDistance; } } // namespace top_domains
diff --git a/components/url_formatter/top_domains/top_domain_util.h b/components/url_formatter/top_domains/top_domain_util.h index f9774ce..33818581 100644 --- a/components/url_formatter/top_domains/top_domain_util.h +++ b/components/url_formatter/top_domains/top_domain_util.h
@@ -15,6 +15,14 @@ // comparison. Will generally return false for short domain names. bool IsEditDistanceCandidate(const std::string& hostname); +// Returns the portion of hostname without the registry part. +// E.g. For hostname = "google.com", the registry is "com", and the return value +// will be "google.". Note that the return value contains a trailing dot. This +// doesn't affect the result when comparing two different domains excluding +// their registries (e.g. when checking google.com.tr and google.com.tw likely +// belong to the same organization). +std::string HostnameWithoutRegistry(const std::string& hostname); + } // namespace top_domains } // namespace url_formatter
diff --git a/components/url_formatter/top_domains/top_domain_util_unittest.cc b/components/url_formatter/top_domains/top_domain_util_unittest.cc new file mode 100644 index 0000000..65e2edc1 --- /dev/null +++ b/components/url_formatter/top_domains/top_domain_util_unittest.cc
@@ -0,0 +1,28 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/url_formatter/top_domains/top_domain_util.h" + +#include "testing/gtest/include/gtest/gtest.h" + +using url_formatter::top_domains::HostnameWithoutRegistry; +using url_formatter::top_domains::IsEditDistanceCandidate; + +TEST(TopDomainUtilTest, IsEditDistanceCandidate) { + EXPECT_FALSE(IsEditDistanceCandidate("")); + EXPECT_TRUE(IsEditDistanceCandidate("google.com")); + // Domain label ("abc") is too short, even though the whole string is long + // enough. + EXPECT_FALSE(IsEditDistanceCandidate("abc.com.tr")); +} + +TEST(TopDomainUtilTest, HostnameWithoutRegistry) { + EXPECT_EQ("google", HostnameWithoutRegistry("google")); + EXPECT_EQ("google.", HostnameWithoutRegistry("google.")); + EXPECT_EQ("google..", HostnameWithoutRegistry("google..")); + EXPECT_EQ("google.", HostnameWithoutRegistry("google.com")); + EXPECT_EQ("google.", HostnameWithoutRegistry("google.com.tr")); + // blogspot.com is a private registry. + EXPECT_EQ("blogspot.", HostnameWithoutRegistry("blogspot.com")); +}
diff --git a/components/viz/client/frame_eviction_manager.cc b/components/viz/client/frame_eviction_manager.cc index dc8c3f8..86c3ed6 100644 --- a/components/viz/client/frame_eviction_manager.cc +++ b/components/viz/client/frame_eviction_manager.cc
@@ -96,8 +96,8 @@ FrameEvictionManager::FrameEvictionManager() : memory_pressure_listener_(new base::MemoryPressureListener( - base::Bind(&FrameEvictionManager::OnMemoryPressure, - base::Unretained(this)))) { + base::BindRepeating(&FrameEvictionManager::OnMemoryPressure, + base::Unretained(this)))) { max_number_of_saved_frames_ = #if defined(OS_ANDROID) // If the amount of memory on the device is >= 3.5 GB, save up to 5
diff --git a/components/viz/common/frame_sinks/delay_based_time_source.cc b/components/viz/common/frame_sinks/delay_based_time_source.cc index eb34c49..ddab391b 100644 --- a/components/viz/common/frame_sinks/delay_based_time_source.cc +++ b/components/viz/common/frame_sinks/delay_based_time_source.cc
@@ -155,8 +155,8 @@ next_tick_time_ += interval_; DCHECK_GT(next_tick_time_, now); } - tick_closure_.Reset(base::Bind(&DelayBasedTimeSource::OnTimerTick, - weak_factory_.GetWeakPtr())); + tick_closure_.Reset(base::BindOnce(&DelayBasedTimeSource::OnTimerTick, + weak_factory_.GetWeakPtr())); task_runner_->PostDelayedTask(FROM_HERE, tick_closure_.callback(), next_tick_time_ - now); }
diff --git a/components/viz/common/frame_sinks/delay_based_time_source.h b/components/viz/common/frame_sinks/delay_based_time_source.h index 7d58a2e..322ad3a 100644 --- a/components/viz/common/frame_sinks/delay_based_time_source.h +++ b/components/viz/common/frame_sinks/delay_based_time_source.h
@@ -76,7 +76,7 @@ base::TimeTicks last_tick_time_; base::TimeTicks next_tick_time_; - base::CancelableClosure tick_closure_; + base::CancelableOnceClosure tick_closure_; base::SingleThreadTaskRunner* task_runner_;
diff --git a/components/viz/common/yuv_readback_unittest.cc b/components/viz/common/yuv_readback_unittest.cc index a780291..fa3ae47d 100644 --- a/components/viz/common/yuv_readback_unittest.cc +++ b/components/viz/common/yuv_readback_unittest.cc
@@ -74,7 +74,7 @@ } static void TraceDataCB( - const base::Callback<void()>& callback, + base::OnceClosure quit_closure, std::string* output, const scoped_refptr<base::RefCountedString>& json_events_str, bool has_more_events) { @@ -83,7 +83,7 @@ } output->append(json_events_str->data()); if (!has_more_events) { - callback.Run(); + std::move(quit_closure).Run(); } } @@ -93,9 +93,9 @@ std::string json_data = "["; base::trace_event::TraceLog::GetInstance()->SetDisabled(); base::RunLoop run_loop; - base::trace_event::TraceLog::GetInstance()->Flush( - base::Bind(&YUVReadbackTest::TraceDataCB, run_loop.QuitClosure(), - base::Unretained(&json_data))); + base::trace_event::TraceLog::GetInstance()->Flush(base::BindRepeating( + &YUVReadbackTest::TraceDataCB, run_loop.QuitClosure(), + base::Unretained(&json_data))); run_loop.Run(); json_data.append("]"); @@ -257,11 +257,6 @@ return ret; } - static void callcallback(const base::Callback<void()>& callback, - bool result) { - callback.Run(); - } - void PrintPlane(unsigned char* plane, int xsize, int stride, int ysize) { for (int y = 0; y < std::min(24, ysize); y++) { std::string formatted; @@ -391,16 +386,20 @@ base::TimeDelta::FromSeconds(0)); base::RunLoop run_loop; - yuv_reader->ReadbackYUV(mailbox, sync_token, gfx::Size(xsize, ysize), - gfx::Rect(0, 0, xsize, ysize), - output_frame->stride(media::VideoFrame::kYPlane), - output_frame->data(media::VideoFrame::kYPlane), - output_frame->stride(media::VideoFrame::kUPlane), - output_frame->data(media::VideoFrame::kUPlane), - output_frame->stride(media::VideoFrame::kVPlane), - output_frame->data(media::VideoFrame::kVPlane), - gfx::Point(xmargin, ymargin), - base::Bind(&callcallback, run_loop.QuitClosure())); + auto run_quit_closure = [](base::OnceClosure quit_closure, bool result) { + std::move(quit_closure).Run(); + }; + yuv_reader->ReadbackYUV( + mailbox, sync_token, gfx::Size(xsize, ysize), + gfx::Rect(0, 0, xsize, ysize), + output_frame->stride(media::VideoFrame::kYPlane), + output_frame->data(media::VideoFrame::kYPlane), + output_frame->stride(media::VideoFrame::kUPlane), + output_frame->data(media::VideoFrame::kUPlane), + output_frame->stride(media::VideoFrame::kVPlane), + output_frame->data(media::VideoFrame::kVPlane), + gfx::Point(xmargin, ymargin), + base::BindOnce(run_quit_closure, run_loop.QuitClosure())); const gfx::Rect paste_rect(gfx::Point(xmargin, ymargin), gfx::Size(xsize, ysize));
diff --git a/components/viz/service/display/copy_output_scaling_pixeltest.cc b/components/viz/service/display/copy_output_scaling_pixeltest.cc index bc136a2..771585a 100644 --- a/components/viz/service/display/copy_output_scaling_pixeltest.cc +++ b/components/viz/service/display/copy_output_scaling_pixeltest.cc
@@ -155,7 +155,7 @@ base::BindOnce( [](bool* dummy_ran, std::unique_ptr<CopyOutputResult>* test_result, - const base::Closure& quit_closure, + const base::RepeatingClosure& quit_closure, std::unique_ptr<CopyOutputResult> result_from_renderer) { EXPECT_TRUE(*dummy_ran); *test_result = std::move(result_from_renderer);
diff --git a/components/viz/service/display/display.cc b/components/viz/service/display/display.cc index 0f8b0b4..9b8780f 100644 --- a/components/viz/service/display/display.cc +++ b/components/viz/service/display/display.cc
@@ -135,13 +135,8 @@ if (scheduler_) surface_manager_->RemoveObserver(scheduler_.get()); } - if (aggregator_) { - for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { - Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first); - if (surface) - surface->RunDrawCallback(); - } - } + + RunDrawCallbacks(); } void Display::Initialize(DisplayClient* client, @@ -382,12 +377,7 @@ swapped_trace_id_); // Run callbacks early to allow pipelining and collect presented callbacks. - for (const auto& surface_id : surfaces_to_ack_on_next_draw_) { - Surface* surface = surface_manager_->GetSurfaceForId(surface_id); - if (surface) - surface->RunDrawCallback(); - } - surfaces_to_ack_on_next_draw_.clear(); + RunDrawCallbacks(); frame.metadata.latency_info.insert(frame.metadata.latency_info.end(), stored_latency_info_.begin(), @@ -829,4 +819,22 @@ std::numeric_limits<uint64_t>::max()))); } +void Display::RunDrawCallbacks() { + for (const auto& surface_id : surfaces_to_ack_on_next_draw_) { + Surface* surface = surface_manager_->GetSurfaceForId(surface_id); + if (surface) + surface->RunDrawCallback(); + } + surfaces_to_ack_on_next_draw_.clear(); + // |surfaces_to_ack_on_next_draw_| does not cover surfaces that are being + // embedded for the first time, so also go through SurfaceAggregator's list. + if (aggregator_) { + for (const auto& id_entry : aggregator_->previous_contained_surfaces()) { + Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first); + if (surface) + surface->RunDrawCallback(); + } + } +} + } // namespace viz
diff --git a/components/viz/service/display/display.h b/components/viz/service/display/display.h index fa336615..6d738d4 100644 --- a/components/viz/service/display/display.h +++ b/components/viz/service/display/display.h
@@ -136,6 +136,7 @@ private: void InitializeRenderer(); void UpdateRootFrameMissing(); + void RunDrawCallbacks(); // ContextLostObserver implementation. void OnContextLost() override;
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc index 29b7c1e3..eb1ba0a9 100644 --- a/components/viz/service/display/display_resource_provider.cc +++ b/components/viz/service/display/display_resource_provider.cc
@@ -522,11 +522,7 @@ metadata.mailbox_holder = resource->transferable.mailbox_holder; metadata.size = resource->transferable.size; - metadata.mip_mapped = GrMipMapped::kNo; - metadata.origin = kTopLeft_GrSurfaceOrigin; metadata.resource_format = resource->transferable.format; - metadata.alpha_type = kPremul_SkAlphaType; - metadata.color_space = nullptr; metadata.mailbox_holder.sync_token = resource->sync_token(); resource->locked_for_external_use = true;
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc index 7c5c22d..3d8ef719 100644 --- a/components/viz/service/display/display_scheduler.cc +++ b/components/viz/service/display/display_scheduler.cc
@@ -36,7 +36,7 @@ wait_for_all_surfaces_before_draw_(wait_for_all_surfaces_before_draw), observing_begin_frame_source_(false), weak_ptr_factory_(this) { - begin_frame_deadline_closure_ = base::Bind( + begin_frame_deadline_closure_ = base::BindRepeating( &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); // The DisplayScheduler handles animate_only BeginFrames as if they were @@ -232,7 +232,7 @@ // CompositorFrame for a SurfaceFactory). DCHECK_EQ(args.type, BeginFrameArgs::MISSED); DCHECK(missed_begin_frame_task_.IsCancelled()); - missed_begin_frame_task_.Reset(base::Bind( + missed_begin_frame_task_.Reset(base::BindOnce( base::IgnoreResult(&DisplayScheduler::OnBeginFrameDerivedImpl), // The CancelableCallback will not run after it is destroyed, which // happens when |this| is destroyed.
diff --git a/components/viz/service/display/display_scheduler.h b/components/viz/service/display/display_scheduler.h index e3a8760..06ffc24 100644 --- a/components/viz/service/display/display_scheduler.h +++ b/components/viz/service/display/display_scheduler.h
@@ -132,11 +132,11 @@ base::SingleThreadTaskRunner* task_runner_; BeginFrameArgs current_begin_frame_args_; - base::Closure begin_frame_deadline_closure_; - base::CancelableClosure begin_frame_deadline_task_; + base::RepeatingClosure begin_frame_deadline_closure_; + base::CancelableOnceClosure begin_frame_deadline_task_; base::TimeTicks begin_frame_deadline_task_time_; - base::CancelableClosure missed_begin_frame_task_; + base::CancelableOnceClosure missed_begin_frame_task_; bool inside_surface_damaged_; bool visible_;
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc index ad03eba..e7c6461 100644 --- a/components/viz/service/display/gl_renderer.cc +++ b/components/viz/service/display/gl_renderer.cc
@@ -3578,7 +3578,8 @@ int max_result = current_surface_size_.GetArea(); DCHECK_GT(max_result, 0); - OverdrawFeedbackCallback overdraw_feedback_callback = base::Bind( + // Callback is repeating to allow sharing the owned vector<int>. + auto overdraw_feedback_callback = base::BindRepeating( &GLRenderer::ProcessOverdrawFeedback, weak_ptr_factory_.GetWeakPtr(), base::Owned(new std::vector<int>), base::size(stencil_tests), max_result);
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h index 85a6599..6aa68062 100644 --- a/components/viz/service/display/gl_renderer.h +++ b/components/viz/service/display/gl_renderer.h
@@ -317,7 +317,6 @@ void SetupOverdrawFeedback(); void FlushOverdrawFeedback(const gfx::Rect& output_rect); // Process overdraw feedback from query. - using OverdrawFeedbackCallback = base::Callback<void(unsigned, int)>; void ProcessOverdrawFeedback(std::vector<int>* overdraw, size_t num_expected_results, int max_result,
diff --git a/components/viz/service/display/gl_renderer_copier_pixeltest.cc b/components/viz/service/display/gl_renderer_copier_pixeltest.cc index 2a4e7378..8c5f5d5 100644 --- a/components/viz/service/display/gl_renderer_copier_pixeltest.cc +++ b/components/viz/service/display/gl_renderer_copier_pixeltest.cc
@@ -251,10 +251,10 @@ result_format_, base::BindOnce( [](std::unique_ptr<CopyOutputResult>* result, - const base::Closure& quit_closure, + base::OnceClosure quit_closure, std::unique_ptr<CopyOutputResult> result_from_copier) { *result = std::move(result_from_copier); - quit_closure.Run(); + std::move(quit_closure).Run(); }, &result, loop.QuitClosure())); if (scale_by_half_) {
diff --git a/components/viz/service/display/gl_renderer_unittest.cc b/components/viz/service/display/gl_renderer_unittest.cc index 3c24c62..b5f0bef 100644 --- a/components/viz/service/display/gl_renderer_unittest.cc +++ b/components/viz/service/display/gl_renderer_unittest.cc
@@ -2399,7 +2399,7 @@ provider->BindToCurrentThread(); MockOverlayScheduler overlay_scheduler; - provider->support()->SetScheduleOverlayPlaneCallback(base::Bind( + provider->support()->SetScheduleOverlayPlaneCallback(base::BindRepeating( &MockOverlayScheduler::Schedule, base::Unretained(&overlay_scheduler))); cc::FakeOutputSurfaceClient output_surface_client;
diff --git a/components/viz/service/display/overlay_unittest.cc b/components/viz/service/display/overlay_unittest.cc index d9619d2b..8a7cc7c 100644 --- a/components/viz/service/display/overlay_unittest.cc +++ b/components/viz/service/display/overlay_unittest.cc
@@ -2862,7 +2862,7 @@ resource_provider_ = std::make_unique<DisplayResourceProvider>( DisplayResourceProvider::kGpu, provider_.get(), nullptr); - provider_->support()->SetScheduleOverlayPlaneCallback(base::Bind( + provider_->support()->SetScheduleOverlayPlaneCallback(base::BindRepeating( &MockOverlayScheduler::Schedule, base::Unretained(&scheduler_))); child_provider_ = TestContextProvider::Create();
diff --git a/components/viz/service/display/resource_metadata.h b/components/viz/service/display/resource_metadata.h index 864dd38..ef8cb4f2 100644 --- a/components/viz/service/display/resource_metadata.h +++ b/components/viz/service/display/resource_metadata.h
@@ -9,9 +9,7 @@ #include "components/viz/service/viz_service_export.h" #include "gpu/command_buffer/common/mailbox_holder.h" #include "gpu/command_buffer/common/sync_token.h" -#include "third_party/skia/include/core/SkColorSpace.h" -#include "third_party/skia/include/core/SkImageInfo.h" -#include "third_party/skia/include/gpu/GrTypes.h" +#include "ui/gfx/color_space.h" #include "ui/gfx/geometry/size.h" namespace viz { @@ -30,20 +28,11 @@ // The resource size. gfx::Size size; - // the mipmap of the resource texture. - GrMipMapped mip_mapped = GrMipMapped::kNo; - - // The origin type for the resource texture. - GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin; - // ResourceFormat from the resource texture. ResourceFormat resource_format = RGBA_8888; - // The alpha type for the resource texture. - SkAlphaType alpha_type = kUnknown_SkAlphaType; - - // The color space for the resource texture. It could be null. - sk_sp<SkColorSpace> color_space; + // The color space for the resource texture. + gfx::ColorSpace color_space; }; } // namespace viz
diff --git a/components/viz/service/display/software_renderer_unittest.cc b/components/viz/service/display/software_renderer_unittest.cc index 5ed0040b..4aff55f 100644 --- a/components/viz/service/display/software_renderer_unittest.cc +++ b/components/viz/service/display/software_renderer_unittest.cc
@@ -112,13 +112,13 @@ } static void SaveBitmapResult(std::unique_ptr<SkBitmap>* bitmap_result, - const base::Closure& quit_closure, + base::OnceClosure quit_closure, std::unique_ptr<CopyOutputResult> result) { DCHECK(!result->IsEmpty()); DCHECK_EQ(result->format(), CopyOutputResult::Format::RGBA_BITMAP); *bitmap_result = std::make_unique<SkBitmap>(result->AsSkBitmap()); DCHECK((*bitmap_result)->readyToDraw()); - quit_closure.Run(); + std::move(quit_closure).Run(); } protected:
diff --git a/components/viz/service/display/texture_deleter.cc b/components/viz/service/display/texture_deleter.cc index 714441f..5545622 100644 --- a/components/viz/service/display/texture_deleter.cc +++ b/components/viz/service/display/texture_deleter.cc
@@ -64,9 +64,9 @@ // The raw pointer to the impl-side callback is valid as long as this // class is alive. So we guard it with a WeakPtr. - ReleaseCallback run_impl_callback( - base::Bind(&TextureDeleter::RunDeleteTextureOnImplThread, - weak_ptr_factory_.GetWeakPtr(), impl_callbacks_.back().get())); + ReleaseCallback run_impl_callback = base::BindOnce( + &TextureDeleter::RunDeleteTextureOnImplThread, + weak_ptr_factory_.GetWeakPtr(), impl_callbacks_.back().get()); // Provide a callback for the main thread that posts back to the impl // thread.
diff --git a/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc b/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc index e0bdbf80..845d211f 100644 --- a/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc +++ b/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.cc
@@ -48,16 +48,16 @@ base::SPLIT_WANT_NONEMPTY)) { if (strategy_name == "single-fullscreen") { strategies_instantiators_.push_back( - base::Bind(MakeOverlayStrategy<OverlayStrategyFullscreen>)); + base::BindRepeating(MakeOverlayStrategy<OverlayStrategyFullscreen>)); } else if (strategy_name == "single-on-top") { strategies_instantiators_.push_back( - base::Bind(MakeOverlayStrategy<OverlayStrategySingleOnTop>)); + base::BindRepeating(MakeOverlayStrategy<OverlayStrategySingleOnTop>)); } else if (strategy_name == "underlay") { strategies_instantiators_.push_back( - base::Bind(MakeOverlayStrategy<OverlayStrategyUnderlay>)); + base::BindRepeating(MakeOverlayStrategy<OverlayStrategyUnderlay>)); } else if (strategy_name == "cast") { - strategies_instantiators_.push_back( - base::Bind(MakeOverlayStrategy<OverlayStrategyUnderlayCast>)); + strategies_instantiators_.push_back(base::BindRepeating( + MakeOverlayStrategy<OverlayStrategyUnderlayCast>)); } else { LOG(WARNING) << "Unrecognized overlay strategy " << strategy_name; }
diff --git a/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h b/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h index 3c03de0..cca7a65 100644 --- a/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h +++ b/components/viz/service/display_embedder/compositor_overlay_candidate_validator_ozone.h
@@ -40,7 +40,7 @@ std::unique_ptr<ui::OverlayCandidatesOzone> overlay_candidates_; // Callback declaration to allocate a new OverlayProcessor::Strategy. using StrategyInstantiator = - base::Callback<std::unique_ptr<OverlayProcessor::Strategy>( + base::RepeatingCallback<std::unique_ptr<OverlayProcessor::Strategy>( CompositorOverlayCandidateValidatorOzone*)>; // List callbacks used to instantiate OverlayProcessor::Strategy // as defined by |strategies_string| paramter in the constructor.
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc index 2bf4861..de5f5ba 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -47,57 +47,100 @@ } // namespace // A helper class for fulfilling promise image on the GPU thread. -template <class FulfillContextType> class SkiaOutputSurfaceImpl::PromiseTextureHelper { public: - using HelperType = PromiseTextureHelper<FulfillContextType>; - - PromiseTextureHelper(base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu, - FulfillContextType context) - : impl_on_gpu_(impl_on_gpu), context_(std::move(context)) {} - ~PromiseTextureHelper() = default; - - static sk_sp<SkImage> MakePromiseSkImage( + static sk_sp<SkImage> MakePromiseSkImageFromMetadata( SkiaOutputSurfaceImpl* impl, - SkDeferredDisplayListRecorder* recorder, - const GrBackendFormat& backend_format, + const ResourceMetadata& metadata) { + auto* helper = new PromiseTextureHelper( + impl->impl_on_gpu_->weak_ptr(), metadata.size, metadata.resource_format, + metadata.mailbox_holder); + return helper->MakePromiseSkImage(impl); + } + + static sk_sp<SkImage> MakePromiseSkImageFromRenderPass( + SkiaOutputSurfaceImpl* impl, + ResourceFormat resource_format, gfx::Size size, - GrMipMapped mip_mapped, - GrSurfaceOrigin origin, - SkColorType color_type, - SkAlphaType alpha_type, - sk_sp<SkColorSpace> color_space, - FulfillContextType context) { + RenderPassId render_pass_id) { DCHECK_CALLED_ON_VALID_THREAD(impl->thread_checker_); // The ownership of the helper will be passed into makePromisTexture(). The - // HelperType::Done will always be called. It will delete the helper. - auto* helper = - new HelperType(impl->impl_on_gpu_->weak_ptr(), std::move(context)); - auto image = recorder->makePromiseTexture( - backend_format, size.width(), size.height(), mip_mapped, origin, - color_type, alpha_type, color_space, HelperType::Fulfill, - HelperType::Release, HelperType::Done, helper); - return image; + // PromiseTextureHelper::Done will always be called. It will delete the + // helper. + auto* helper = new PromiseTextureHelper( + impl->impl_on_gpu_->weak_ptr(), size, resource_format, render_pass_id); + return helper->MakePromiseSkImage(impl); } private: friend class SkiaOutputSurfaceImpl::YUVAPromiseTextureHelper; + PromiseTextureHelper(base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu, + const gfx::Size& size, + ResourceFormat resource_format, + RenderPassId render_pass_id) + : impl_on_gpu_(impl_on_gpu), + size_(size), + resource_format_(resource_format), + render_pass_id_(render_pass_id) {} + PromiseTextureHelper(base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu, + const gfx::Size& size, + ResourceFormat resource_format, + const gpu::MailboxHolder& mailbox_holder) + : impl_on_gpu_(impl_on_gpu), + size_(size), + resource_format_(resource_format), + render_pass_id_(0u), + mailbox_holder_(mailbox_holder) {} + ~PromiseTextureHelper() = default; + + sk_sp<SkImage> MakePromiseSkImage(SkiaOutputSurfaceImpl* impl) { + SkColorType color_type = ResourceFormatToClosestSkColorType( + true /* gpu_compositing */, resource_format_); + GrBackendFormat backend_format; + if (!impl->gpu_service_->is_using_vulkan()) { + // Convert internal format from GLES2 to platform GL. + const auto* version_info = impl->impl_on_gpu_->gl_version_info(); + unsigned int texture_storage_format = + TextureStorageFormat(resource_format_); + backend_format = GrBackendFormat::MakeGL( + gl::GetInternalFormat(version_info, texture_storage_format), + GL_TEXTURE_2D); + } else { +#if BUILDFLAG(ENABLE_VULKAN) + backend_format = GrBackendFormat::MakeVk(ToVkFormat(resource_format_)); +#else + NOTREACHED(); +#endif + } + return impl->recorder_->makePromiseTexture( + backend_format, size_.width(), size_.height(), GrMipMapped::kNo, + kTopLeft_GrSurfaceOrigin /* origin */, color_type, kPremul_SkAlphaType, + nullptr /* color_space */, PromiseTextureHelper::Fulfill, + PromiseTextureHelper::Release, PromiseTextureHelper::Done, this); + } + static void Fulfill(void* texture_context, GrBackendTexture* backend_texture) { DCHECK(texture_context); - auto* helper = static_cast<HelperType*>(texture_context); + auto* helper = static_cast<PromiseTextureHelper*>(texture_context); // The fulfill is always called by SkiaOutputSurfaceImplOnGpu::SwapBuffers // or SkiaOutputSurfaceImplOnGpu::FinishPaintRenderPass, so impl_on_gpu_ // should be always valid. DCHECK(helper->impl_on_gpu_); - helper->impl_on_gpu_->FulfillPromiseTexture( - helper->context_, &helper->shared_image_, backend_texture); + if (helper->render_pass_id_) { + helper->impl_on_gpu_->FulfillPromiseTexture( + helper->render_pass_id_, &helper->shared_image_, backend_texture); + } else { + helper->impl_on_gpu_->FulfillPromiseTexture( + helper->mailbox_holder_, helper->size_, helper->resource_format_, + &helper->shared_image_, backend_texture); + } } static void Release(void* texture_context) { DCHECK(texture_context); - auto* helper = static_cast<HelperType*>(texture_context); + auto* helper = static_cast<PromiseTextureHelper*>(texture_context); if (helper->shared_image_) { helper->shared_image_->EndReadAccess(); helper->shared_image_.reset(); @@ -106,14 +149,15 @@ static void Done(void* texture_context) { DCHECK(texture_context); - std::unique_ptr<HelperType> helper( - static_cast<HelperType*>(texture_context)); + auto* helper = static_cast<PromiseTextureHelper*>(texture_context); + delete helper; } base::WeakPtr<SkiaOutputSurfaceImplOnGpu> impl_on_gpu_; - - // The data for calling the fulfill methods in SkiaOutputSurfaceImpl. - FulfillContextType context_; + const gfx::Size size_; + const ResourceFormat resource_format_; + RenderPassId render_pass_id_; + gpu::MailboxHolder mailbox_holder_; // If non-null, an outstanding SharedImageRepresentation that must be freed on // Release. Only written / read from GPU thread. @@ -127,14 +171,12 @@ public: static sk_sp<SkImage> MakeYUVAPromiseSkImage( SkiaOutputSurfaceImpl* impl, - SkDeferredDisplayListRecorder* recorder, SkYUVColorSpace yuv_color_space, std::vector<ResourceMetadata> metadatas, bool has_alpha) { DCHECK_CALLED_ON_VALID_THREAD(impl->thread_checker_); DCHECK_LE(metadatas.size(), 4u); - using PlaneHelper = PromiseTextureHelper<ResourceMetadata>; bool is_i420 = has_alpha ? metadatas.size() == 4 : metadatas.size() == 3; GrBackendFormat formats[4]; @@ -149,8 +191,8 @@ nullptr, nullptr, nullptr, nullptr}; // The ownership of the contexts will be passed into - // makeYUVAPromisTexture(). The HelperType::Done will always be called. It - // will delete contexts. + // makeYUVAPromiseTexture(). The PromiseTextureHelper::Done will always be + // called. It will delete contexts. const auto process_planar = [&](size_t i, ResourceFormat resource_format, GLenum gl_format) { auto& metadata = metadatas[i]; @@ -158,8 +200,9 @@ formats[i] = GrBackendFormat::MakeGL( gl_format, metadata.mailbox_holder.texture_target); yuva_sizes[i].set(metadata.size.width(), metadata.size.height()); - contexts[i] = - new PlaneHelper(impl->impl_on_gpu_->weak_ptr(), std::move(metadata)); + contexts[i] = new PromiseTextureHelper( + impl->impl_on_gpu_->weak_ptr(), metadata.size, + metadata.resource_format, metadata.mailbox_holder); }; if (is_i420) { @@ -197,11 +240,11 @@ } } - auto image = recorder->makeYUVAPromiseTexture( + auto image = impl->recorder_->makeYUVAPromiseTexture( yuv_color_space, formats, yuva_sizes, indices, yuva_sizes[0].width(), yuva_sizes[0].height(), kTopLeft_GrSurfaceOrigin, - nullptr /* color_space */, PlaneHelper::Fulfill, PlaneHelper::Release, - PlaneHelper::Done, contexts); + nullptr /* color_space */, PromiseTextureHelper::Fulfill, + PromiseTextureHelper::Release, PromiseTextureHelper::Done, contexts); return image; } @@ -397,32 +440,9 @@ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(recorder_); - GrBackendFormat backend_format; - if (!gpu_service_->is_using_vulkan()) { - // Convert internal format from GLES2 to platform GL. - const auto* version_info = impl_on_gpu_->gl_version_info(); - backend_format = GrBackendFormat::MakeGL( - gl::GetInternalFormat(version_info, - TextureStorageFormat(metadata.resource_format)), - metadata.mailbox_holder.texture_target); - } else { -#if BUILDFLAG(ENABLE_VULKAN) - backend_format = - GrBackendFormat::MakeVk(ToVkFormat(metadata.resource_format)); -#else - NOTREACHED(); -#endif - } - DCHECK(!metadata.mailbox_holder.mailbox.IsZero()); resource_sync_tokens_.push_back(metadata.mailbox_holder.sync_token); - SkColorType sk_color_type = ResourceFormatToClosestSkColorType( - /*gpu_compositing=*/true, metadata.resource_format); - - return PromiseTextureHelper<ResourceMetadata>::MakePromiseSkImage( - this, &recorder_.value(), backend_format, metadata.size, - metadata.mip_mapped, metadata.origin, sk_color_type, metadata.alpha_type, - metadata.color_space, std::move(metadata)); + return PromiseTextureHelper::MakePromiseSkImageFromMetadata(this, metadata); } sk_sp<SkImage> SkiaOutputSurfaceImpl::MakePromiseSkImageFromYUV( @@ -435,8 +455,7 @@ (!has_alpha && (metadatas.size() == 2 || metadatas.size() == 3))); return YUVAPromiseTextureHelper::MakeYUVAPromiseSkImage( - this, &recorder_.value(), yuv_color_space, std::move(metadatas), - has_alpha); + this, yuv_color_space, std::move(metadatas), has_alpha); } void SkiaOutputSurfaceImpl::SkiaSwapBuffers(OutputSurfaceFrame frame) { @@ -524,29 +543,11 @@ bool mipmap) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(recorder_); + // TODO(penghuang): remove this mipmap argument, because we always pass false. + DCHECK(!mipmap); - SkColorType color_type = - ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format); - GrBackendFormat backend_format; - - if (!gpu_service_->is_using_vulkan()) { - // Convert internal format from GLES2 to platform GL. - const auto* version_info = impl_on_gpu_->gl_version_info(); - unsigned int texture_storage_format = TextureStorageFormat(format); - backend_format = GrBackendFormat::MakeGL( - gl::GetInternalFormat(version_info, texture_storage_format), - GL_TEXTURE_2D); - } else { -#if BUILDFLAG(ENABLE_VULKAN) - backend_format = GrBackendFormat::MakeVk(ToVkFormat(format)); -#else - NOTREACHED(); -#endif - } - return PromiseTextureHelper<RenderPassId>::MakePromiseSkImage( - this, &recorder_.value(), backend_format, size, - mipmap ? GrMipMapped::kYes : GrMipMapped::kNo, kTopLeft_GrSurfaceOrigin, - color_type, kPremul_SkAlphaType, nullptr /* color_space */, id); + return PromiseTextureHelper::MakePromiseSkImageFromRenderPass(this, format, + size, id); } void SkiaOutputSurfaceImpl::RemoveRenderPassResource(
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h index 22d7495..31a0a65 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -99,7 +99,6 @@ void RemoveContextLostObserver(ContextLostObserver* observer) override; private: - template <class T> class PromiseTextureHelper; class YUVAPromiseTextureHelper; void InitializeOnGpuThread(base::WaitableEvent* event); @@ -151,6 +150,7 @@ // Whether to send OutputSurfaceClient::DidSwapWithSize notifications. bool needs_swap_size_notifications_ = false; + // Observers for context lost. base::ObserverList<ContextLostObserver>::Unchecked observers_; THREAD_CHECKER(thread_checker_);
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc index f18f8c5e..fdb9272 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.cc
@@ -414,16 +414,18 @@ } void SkiaOutputSurfaceImplOnGpu::FulfillPromiseTexture( - const ResourceMetadata& metadata, + const gpu::MailboxHolder& mailbox_holder, + const gfx::Size& size, + const ResourceFormat resource_format, std::unique_ptr<gpu::SharedImageRepresentationSkia>* shared_image_out, GrBackendTexture* backend_texture) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); DCHECK(!*shared_image_out); if (shared_image_representation_factory_->IsSharedImage( - metadata.mailbox_holder.mailbox)) { + mailbox_holder.mailbox)) { std::unique_ptr<gpu::SharedImageRepresentationSkia> shared_image = shared_image_representation_factory_->ProduceSkia( - metadata.mailbox_holder.mailbox); + mailbox_holder.mailbox); DCHECK(shared_image); if (!shared_image->BeginReadAccess(sk_surface_.get(), backend_texture)) { DLOG(ERROR) @@ -442,16 +444,15 @@ } auto* mailbox_manager = gpu_service_->mailbox_manager(); - auto* texture_base = - mailbox_manager->ConsumeTexture(metadata.mailbox_holder.mailbox); + auto* texture_base = mailbox_manager->ConsumeTexture(mailbox_holder.mailbox); if (!texture_base) { DLOG(ERROR) << "Failed to fulfill the promise texture."; return; } BindOrCopyTextureIfNecessary(texture_base); - gpu::GetGrBackendTexture(gl_version_info_, texture_base->target(), - metadata.size, texture_base->service_id(), - metadata.resource_format, backend_texture); + gpu::GetGrBackendTexture(gl_version_info_, texture_base->target(), size, + texture_base->service_id(), resource_format, + backend_texture); } void SkiaOutputSurfaceImplOnGpu::FulfillPromiseTexture(
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h index 6fac3e6..3b9422a 100644 --- a/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h +++ b/components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h
@@ -109,7 +109,9 @@ // Fulfill callback for promise SkImage created from a resource. void FulfillPromiseTexture( - const ResourceMetadata& metadata, + const gpu::MailboxHolder& mailbox_holder, + const gfx::Size& size, + const ResourceFormat resource_format, std::unique_ptr<gpu::SharedImageRepresentationSkia>* shared_image_out, GrBackendTexture* backend_texture); // Fulfill callback for promise SkImage created from a render pass.
diff --git a/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc b/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc index 1b4e644..273beda 100644 --- a/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc +++ b/components/viz/service/frame_sinks/external_begin_frame_source_android_unittest.cc
@@ -21,16 +21,17 @@ thread_->task_runner()->PostTask( FROM_HERE, - base::Bind(&ExternalBeginFrameSourceAndroidTest::InitOnThread, - base::Unretained(this))); + base::BindOnce(&ExternalBeginFrameSourceAndroidTest::InitOnThread, + base::Unretained(this))); } void WaitForFrames(uint32_t frame_count) { frames_done_event_.Reset(); thread_->task_runner()->PostTask( FROM_HERE, - base::Bind(&ExternalBeginFrameSourceAndroidTest::AddObserverOnThread, - base::Unretained(this), frame_count)); + base::BindOnce( + &ExternalBeginFrameSourceAndroidTest::AddObserverOnThread, + base::Unretained(this), frame_count)); frames_done_event_.Wait(); }
diff --git a/components/viz/service/gl/gpu_service_impl.cc b/components/viz/service/gl/gpu_service_impl.cc index 0fe9bd6..ba02e1f 100644 --- a/components/viz/service/gl/gpu_service_impl.cc +++ b/components/viz/service/gl/gpu_service_impl.cc
@@ -84,7 +84,7 @@ namespace { -static base::LazyInstance<base::Callback< +static base::LazyInstance<base::RepeatingCallback< void(int severity, size_t message_start, const std::string& message)>>:: Leaky g_log_callback = LAZY_INSTANCE_INITIALIZER; @@ -171,8 +171,7 @@ DCHECK(main_runner_->BelongsToCurrentThread()); bind_task_tracker_.TryCancelAll(); logging::SetLogMessageHandler(nullptr); - g_log_callback.Get() = - base::Callback<void(int, size_t, const std::string&)>(); + g_log_callback.Get().Reset(); base::WaitableEvent wait; if (io_runner_->PostTask( FROM_HERE, base::BindOnce(&DestroyBinding, bindings_.get(), &wait))) { @@ -232,8 +231,8 @@ // The global callback is reset from the dtor. So Unretained() here is safe. // Note that the callback can be called from any thread. Consequently, the // callback cannot use a WeakPtr. - g_log_callback.Get() = - base::Bind(&GpuServiceImpl::RecordLogMessage, base::Unretained(this)); + g_log_callback.Get() = base::BindRepeating( + &GpuServiceImpl::RecordLogMessage, base::Unretained(this)); logging::SetLogMessageHandler(GpuLogMessageHandler); } @@ -422,7 +421,7 @@ DCHECK(io_runner_->BelongsToCurrentThread()); media::MojoVideoEncodeAcceleratorProvider::Create( std::move(vea_provider_request), - base::Bind(&media::GpuVideoEncodeAcceleratorFactory::CreateVEA), + base::BindRepeating(&media::GpuVideoEncodeAcceleratorFactory::CreateVEA), gpu_preferences_); }
diff --git a/components/viz/service/main/BUILD.gn b/components/viz/service/main/BUILD.gn index a9aa094..13b0a2796 100644 --- a/components/viz/service/main/BUILD.gn +++ b/components/viz/service/main/BUILD.gn
@@ -25,7 +25,7 @@ "//components/discardable_memory/client", "//components/discardable_memory/public/interfaces", "//components/ui_devtools", - "//components/ui_devtools/viz_views", + "//components/ui_devtools/viz", "//components/viz/service", "//gpu/ipc:gl_in_process_context", "//gpu/ipc/common",
diff --git a/components/viz/service/main/viz_compositor_thread_runner.cc b/components/viz/service/main/viz_compositor_thread_runner.cc index 47ecab5..70b6b86 100644 --- a/components/viz/service/main/viz_compositor_thread_runner.cc +++ b/components/viz/service/main/viz_compositor_thread_runner.cc
@@ -25,8 +25,8 @@ #if defined(USE_VIZ_DEVTOOLS) #include "components/ui_devtools/css_agent.h" #include "components/ui_devtools/devtools_server.h" -#include "components/ui_devtools/viz_views/dom_agent_viz.h" -#include "components/ui_devtools/viz_views/overlay_agent_viz.h" +#include "components/ui_devtools/viz/dom_agent_viz.h" +#include "components/ui_devtools/viz/overlay_agent_viz.h" #endif namespace viz {
diff --git a/components/viz/test/fake_external_begin_frame_source.cc b/components/viz/test/fake_external_begin_frame_source.cc index 75a0b0d..0f22be5 100644 --- a/components/viz/test/fake_external_begin_frame_source.cc +++ b/components/viz/test/fake_external_begin_frame_source.cc
@@ -99,12 +99,11 @@ void FakeExternalBeginFrameSource::PostTestOnBeginFrame() { begin_frame_task_.Reset( - base::Bind(&FakeExternalBeginFrameSource::TestOnBeginFrame, - weak_ptr_factory_.GetWeakPtr())); + base::BindOnce(&FakeExternalBeginFrameSource::TestOnBeginFrame, + weak_ptr_factory_.GetWeakPtr(), + CreateBeginFrameArgs(BEGINFRAME_FROM_HERE))); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - base::BindOnce(begin_frame_task_.callback(), - CreateBeginFrameArgs(BEGINFRAME_FROM_HERE)), + FROM_HERE, begin_frame_task_.callback(), base::TimeDelta::FromMilliseconds(milliseconds_per_frame_)); next_begin_frame_number_++; }
diff --git a/components/viz/test/fake_external_begin_frame_source.h b/components/viz/test/fake_external_begin_frame_source.h index 39f893b..47b43fa 100644 --- a/components/viz/test/fake_external_begin_frame_source.h +++ b/components/viz/test/fake_external_begin_frame_source.h
@@ -61,7 +61,7 @@ BeginFrameArgs current_args_; uint64_t next_begin_frame_number_ = BeginFrameArgs::kStartingFrameNumber; std::set<BeginFrameObserver*> observers_; - base::CancelableCallback<void(const BeginFrameArgs&)> begin_frame_task_; + base::CancelableOnceClosure begin_frame_task_; SEQUENCE_CHECKER(sequence_checker_);
diff --git a/components/viz/test/test_context_support.cc b/components/viz/test/test_context_support.cc index 31c7b295..bf92ee2 100644 --- a/components/viz/test/test_context_support.cc +++ b/components/viz/test/test_context_support.cc
@@ -105,7 +105,7 @@ return false; } -void* TestContextSupport::MapTransferCacheEntry(size_t serialized_size) { +void* TestContextSupport::MapTransferCacheEntry(uint32_t serialized_size) { NOTIMPLEMENTED(); return nullptr; }
diff --git a/components/viz/test/test_context_support.h b/components/viz/test/test_context_support.h index e9e4d63..c69c4437 100644 --- a/components/viz/test/test_context_support.h +++ b/components/viz/test/test_context_support.h
@@ -68,7 +68,7 @@ uint32_t texture_id) override; bool ThreadsafeDiscardableTextureIsDeletedForTracing( uint32_t texture_id) override; - void* MapTransferCacheEntry(size_t serialized_size) override; + void* MapTransferCacheEntry(uint32_t serialized_size) override; void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override; bool ThreadsafeLockTransferCacheEntry(uint32_t entry_type, uint32_t entry_id) override;
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn index 07f209d..b20ddba 100644 --- a/content/browser/BUILD.gn +++ b/content/browser/BUILD.gn
@@ -1008,12 +1008,12 @@ "indexed_db/indexed_db_transaction_coordinator.h", "indexed_db/indexed_db_value.cc", "indexed_db/indexed_db_value.h", + "indexed_db/leveldb/leveldb_comparator.cc", "indexed_db/leveldb/leveldb_comparator.h", "indexed_db/leveldb/leveldb_database.cc", "indexed_db/leveldb/leveldb_database.h", "indexed_db/leveldb/leveldb_env.cc", "indexed_db/leveldb/leveldb_env.h", - "indexed_db/leveldb/leveldb_factory.h", "indexed_db/leveldb/leveldb_iterator.cc", "indexed_db/leveldb/leveldb_iterator.h", "indexed_db/leveldb/leveldb_iterator_impl.cc", @@ -1025,6 +1025,8 @@ "indexed_db/list_set.h", "indexed_db/scopes/disjoint_range_lock_manager.cc", "indexed_db/scopes/disjoint_range_lock_manager.h", + "indexed_db/scopes/leveldb_state.cc", + "indexed_db/scopes/leveldb_state.h", "indexed_db/scopes/scope_lock.cc", "indexed_db/scopes/scope_lock.h", "indexed_db/scopes/scope_lock_range.cc",
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 3c0f81b..8afe258 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -1187,6 +1187,14 @@ return accessibility_state->disable_hot_tracking_for_testing(); } +bool BrowserAccessibility::IsOrderedSetItem() const { + return node()->IsOrderedSetItem(); +} + +bool BrowserAccessibility::IsOrderedSet() const { + return node()->IsOrderedSet(); +} + int32_t BrowserAccessibility::GetPosInSet() const { return node()->GetPosInSet(); }
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 6c7d3b4..e5e5d4a3 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h
@@ -383,6 +383,8 @@ int32_t dst_id) override; std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) override; + bool IsOrderedSetItem() const override; + bool IsOrderedSet() const override; int32_t GetPosInSet() const override; int32_t GetSetSize() const override;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 0d9cc373..9e5070b 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -1198,13 +1198,11 @@ if (![self instanceActive]) return nil; if ([self internalRole] == ax::mojom::Role::kColumn) { - int columnIndex = - owner_->GetIntAttribute(ax::mojom::IntAttribute::kTableColumnIndex); - return [NSNumber numberWithInt:columnIndex]; + DCHECK(owner_->node()); + return @(owner_->node()->GetTableColColIndex()); } else if ([self internalRole] == ax::mojom::Role::kRow) { - int rowIndex = - owner_->GetIntAttribute(ax::mojom::IntAttribute::kTableRowIndex); - return [NSNumber numberWithInt:rowIndex]; + DCHECK(owner_->node()); + return @(owner_->node()->GetTableRowRowIndex()); } return nil;
diff --git a/content/browser/dom_storage/storage_area_impl.cc b/content/browser/dom_storage/storage_area_impl.cc index b5cff87..c7e1ce3 100644 --- a/content/browser/dom_storage/storage_area_impl.cc +++ b/content/browser/dom_storage/storage_area_impl.cc
@@ -84,8 +84,8 @@ commit_rate_limiter_(options.max_commits_per_hour, base::TimeDelta::FromHours(1)), weak_ptr_factory_(this) { - bindings_.set_connection_error_handler( - base::Bind(&StorageAreaImpl::OnConnectionError, base::Unretained(this))); + bindings_.set_connection_error_handler(base::BindRepeating( + &StorageAreaImpl::OnConnectionError, weak_ptr_factory_.GetWeakPtr())); } StorageAreaImpl::~StorageAreaImpl() { @@ -146,7 +146,7 @@ void StorageAreaImpl::ScheduleImmediateCommit() { if (!on_load_complete_tasks_.empty()) { LoadMap(base::BindOnce(&StorageAreaImpl::ScheduleImmediateCommit, - base::Unretained(this))); + weak_ptr_factory_.GetWeakPtr())); return; } @@ -240,9 +240,9 @@ const std::string& source, PutCallback callback) { if (!IsMapLoaded() || IsMapUpgradeNeeded()) { - LoadMap(base::BindOnce(&StorageAreaImpl::Put, base::Unretained(this), key, - value, client_old_value, source, - std::move(callback))); + LoadMap(base::BindOnce(&StorageAreaImpl::Put, + weak_ptr_factory_.GetWeakPtr(), key, value, + client_old_value, source, std::move(callback))); return; } @@ -357,8 +357,9 @@ // |client_old_value| can race. Thus any changes require checking for an // upgrade. if (!IsMapLoaded() || IsMapUpgradeNeeded()) { - LoadMap(base::BindOnce(&StorageAreaImpl::Delete, base::Unretained(this), - key, client_old_value, source, std::move(callback))); + LoadMap(base::BindOnce(&StorageAreaImpl::Delete, + weak_ptr_factory_.GetWeakPtr(), key, + client_old_value, source, std::move(callback))); return; } @@ -423,8 +424,9 @@ // Don't check if a map upgrade is needed here and instead just create an // empty map ourself. if (!IsMapLoaded()) { - LoadMap(base::BindOnce(&StorageAreaImpl::DeleteAll, base::Unretained(this), - source, std::move(callback))); + LoadMap(base::BindOnce(&StorageAreaImpl::DeleteAll, + weak_ptr_factory_.GetWeakPtr(), source, + std::move(callback))); return; } @@ -468,7 +470,8 @@ return; } if (!IsMapLoaded() || IsMapUpgradeNeeded()) { - LoadMap(base::BindOnce(&StorageAreaImpl::Get, base::Unretained(this), key, + LoadMap(base::BindOnce(&StorageAreaImpl::Get, + weak_ptr_factory_.GetWeakPtr(), key, std::move(callback))); return; } @@ -486,7 +489,8 @@ GetAllCallback callback) { // The map must always be loaded for the KEYS_ONLY_WHEN_POSSIBLE mode. if (map_state_ != MapState::LOADED_KEYS_AND_VALUES) { - LoadMap(base::BindOnce(&StorageAreaImpl::GetAll, base::Unretained(this), + LoadMap(base::BindOnce(&StorageAreaImpl::GetAll, + weak_ptr_factory_.GetWeakPtr(), std::move(complete_callback), std::move(callback))); return; }
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc index 70fc8ad..6cdb9cd 100644 --- a/content/browser/download/download_browsertest.cc +++ b/content/browser/download/download_browsertest.cc
@@ -2146,27 +2146,27 @@ parameters.injected_errors.pop(); TestDownloadHttpResponse::StartServing(parameters, server_url2); - download->Resume(false); + download->Resume(true); WaitForInterrupt(download); parameters.injected_errors.pop(); TestDownloadHttpResponse::StartServing(parameters, server_url2); - download->Resume(false); + download->Resume(true); WaitForInterrupt(download); parameters.injected_errors.pop(); TestDownloadHttpResponse::StartServing(parameters, server_url2); - download->Resume(false); + download->Resume(true); WaitForInterrupt(download); parameters.injected_errors.pop(); TestDownloadHttpResponse::StartServing(parameters, server_url2); - download->Resume(false); + download->Resume(true); WaitForInterrupt(download); parameters.injected_errors.pop(); TestDownloadHttpResponse::StartServing(parameters, server_url2); - download->Resume(false); + download->Resume(true); WaitForCompletion(download); EXPECT_EQ(expected_hash, download->GetHash());
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc index 644ddcb9..163932d 100644 --- a/content/browser/download/download_manager_impl.cc +++ b/content/browser/download/download_manager_impl.cc
@@ -774,11 +774,6 @@ return browser_context_->IsOffTheRecord(); } -bool DownloadManagerImpl::IsActiveNetworkMetered() const { - // TODO(shaktisahu): Call ChromeDownloadManagerDelegate to get this. - return false; -} - void DownloadManagerImpl::ReportBytesWasted( download::DownloadItemImpl* download) { in_progress_manager_->ReportBytesWasted(download);
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h index d596137..b94e85cf 100644 --- a/content/browser/download/download_manager_impl.h +++ b/content/browser/download/download_manager_impl.h
@@ -257,7 +257,6 @@ base::Optional<download::DownloadEntry> GetInProgressEntry( download::DownloadItemImpl* download) override; bool IsOffTheRecord() const override; - bool IsActiveNetworkMetered() const override; void ReportBytesWasted(download::DownloadItemImpl* download) override; // Drops a download before it is created.
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc index f9c428a3..7d36042 100644 --- a/content/browser/frame_host/navigation_handle_impl.cc +++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -457,7 +457,10 @@ } net::HostPortPair NavigationHandleImpl::GetSocketAddress() { - DCHECK(state_ >= WILL_PROCESS_RESPONSE); + // This is CANCELING because although the data comes in after + // WILL_PROCESS_RESPONSE, it's possible for the navigation to be cancelled + // after and the caller might want this value. + DCHECK(state_ >= CANCELING); return socket_address_; }
diff --git a/content/browser/indexed_db/docs/open_and_verify_leveldb_database.code2flow b/content/browser/indexed_db/docs/open_and_verify_leveldb_database.code2flow new file mode 100644 index 0000000..bb2e241 --- /dev/null +++ b/content/browser/indexed_db/docs/open_and_verify_leveldb_database.code2flow
@@ -0,0 +1,112 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// open_and_verify_leveldb_database.pdf was created from this file by +// https://www.code2flow.com/app + +function OpenLevelDB { + |Read free disk space|; + Histogram(FreeDiskSpace); + switch (leveldb_env::OpenDB) { + case Status Not OK:{ + Histogram(LevelDBOpenErrors); + if (disk space < 100kb) + Report disk space as failure reason; + return leveldb_env::OpenDB error status; + } + case Status OK: { + Histogram(LevelDB.OpenTime); + return Status::OK; + } + } +} + +OpenAndVerifyLevelDBDatabase; +switch (Create IDB Directory) { + case Failure: + Histogram(FAILED_DIRECTORY); + return IOError("Unable to create IndexedDB database path"); + case Success: +} +Create File path & blob path; +if (File Path is too long) { + Histogram(ORIGIN_TOO_LONG); + return IOError("File path too long); +} + +call OpenLevelDB; + +switch(OpenLevelDB status) { + case IOError: + Histogram(OPEN_NO_RECOVERY); + return OpenLevelDB error status; + case Corruption: + Set data loss info; + break; + case OK: + if (Corruption Info Exists & Last Open was corrupt) { + Histogram(FAILED_PRIOR_CORRUPTION); + db_.reset(); + Populate data loss info + (previous corruption); + break; + } + switch (try to read schema) { + case Failure reading schema: + Histogram(FAILED_IO_ERROR_CHECKING_SCHEMA); + db_.reset(); + Populate data loss info + (schema checking failure); + break; + case Schema is unknown: + Histogram(FAILED_UNKNOWN_SCHEMA); + db_.reset(); + Populate data loss info + (unknown schema); + break; + case Success & Valid: + Histogram(OPEN_SUCCESS); + goto end; + } +} +switch(DestroyLevelDB(file_path)) { + case Not OK: + Histogram(CLEANUP_DESTROY_FAILED); + return DestroyLevelDB error status; + case OK: +} +call OpenLevelDB; +switch(OpenLevelDB status) { + case Not OK: + Histogram(CLEANUP_REOPEN_FAILED); + return OpenLevelDB error status; + case OK: + Histogram(CLEANUP_REOPEN_SUCCESS); +} + +end: +Histogram(OPEN_SUCCESS); +block { +Create BackingStore; +switch (Parse schema & metadata) { + case Failure: + Delete Database & BackingStore; + break; + case Success: + if (Should we clean blob journal?) { + switch(CleanUpBlobJournal) { + case OK: + report `Status::OK`; + goto done; + case Not OK: + Histogram(FAILED_CLEANUP_JOURNAL_ERROR); + return CleanUpBlobJournal error status; + } + } +} +return BackingStore error status; +} + +done: +return done; \ No newline at end of file
diff --git a/content/browser/indexed_db/docs/open_and_verify_leveldb_database.pdf b/content/browser/indexed_db/docs/open_and_verify_leveldb_database.pdf new file mode 100644 index 0000000..29ba7e5 --- /dev/null +++ b/content/browser/indexed_db/docs/open_and_verify_leveldb_database.pdf Binary files differ
diff --git a/content/browser/indexed_db/indexed_db_backing_store.cc b/content/browser/indexed_db/indexed_db_backing_store.cc index 0654cb3..0e48fa7 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_backing_store.cc
@@ -36,7 +36,6 @@ #include "content/browser/indexed_db/indexed_db_value.h" #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" #include "content/browser/indexed_db/leveldb/leveldb_database.h" -#include "content/browser/indexed_db/leveldb/leveldb_factory.h" #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" #include "content/public/browser/browser_task_traits.h" @@ -65,21 +64,21 @@ using url::Origin; namespace content { -using indexed_db::CheckObjectStoreAndMetaDataType; using indexed_db::CheckIndexAndMetaDataKey; +using indexed_db::CheckObjectStoreAndMetaDataType; using indexed_db::FindGreatestKeyLessThanOrEqual; using indexed_db::GetInt; using indexed_db::GetString; using indexed_db::GetVarInt; -using indexed_db::HistogramOpenStatus; -using indexed_db::IOErrorStatus; using indexed_db::InternalInconsistencyStatus; using indexed_db::InvalidDBKeyStatus; +using indexed_db::IOErrorStatus; using indexed_db::PutBool; -using indexed_db::PutInt; -using indexed_db::PutVarInt; -using indexed_db::PutString; using indexed_db::PutIDBKeyPath; +using indexed_db::PutInt; +using indexed_db::PutString; +using indexed_db::PutVarInt; +using indexed_db::ReportOpenStatus; namespace { @@ -115,44 +114,6 @@ return storage::GetIdentifierFromOrigin(origin) + "@1"; } -FilePath ComputeCorruptionFileName(const Origin& origin) { - return IndexedDBContextImpl::GetLevelDBFileName(origin).Append( - FILE_PATH_LITERAL("corruption_info.json")); -} - -WARN_UNUSED_RESULT bool IsSchemaKnown(LevelDBDatabase* db, bool* known) { - int64_t db_schema_version = 0; - bool found = false; - Status s = GetInt(db, SchemaVersionKey::Encode(), &db_schema_version, &found); - if (!s.ok()) - return false; - if (!found) { - *known = true; - return true; - } - if (db_schema_version < 0) - return false; // Only corruption should cause this. - if (db_schema_version > indexed_db::kLatestKnownSchemaVersion) { - *known = false; - return true; - } - - int64_t raw_db_data_version = 0; - s = GetInt(db, DataVersionKey::Encode(), &raw_db_data_version, &found); - if (!s.ok()) - return false; - if (!found) { - *known = true; - return true; - } - if (raw_db_data_version < 0) - return false; // Only corruption should cause this. - - *known = IndexedDBDataFormatVersion::GetCurrent().IsAtLeast( - IndexedDBDataFormatVersion::Decode(raw_db_data_version)); - return true; -} - // TODO(ericu): Error recovery. If we persistently can't read the // blob journal, the safe thing to do is to clear it and leak the blobs, // though that may be costly. Still, database/directory deletion should always @@ -548,31 +509,11 @@ } // namespace -class DefaultLevelDBFactory : public LevelDBFactory { - public: - DefaultLevelDBFactory() {} - Status OpenLevelDB(const FilePath& file_name, - const LevelDBComparator* comparator, - std::unique_ptr<LevelDBDatabase>* db, - bool* is_disk_full) override { - return LevelDBDatabase::Open( - file_name, comparator, - LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase, db, is_disk_full); - } - Status DestroyLevelDB(const FilePath& file_name) override { - return LevelDBDatabase::Destroy(file_name); - } - - private: - DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory); -}; - IndexedDBBackingStore::IndexedDBBackingStore( IndexedDBFactory* indexed_db_factory, const Origin& origin, const FilePath& blob_path, std::unique_ptr<LevelDBDatabase> db, - std::unique_ptr<LevelDBComparator> comparator, base::SequencedTaskRunner* task_runner) : indexed_db_factory_(indexed_db_factory), origin_(origin), @@ -580,7 +521,6 @@ origin_identifier_(ComputeOriginIdentifier(origin)), task_runner_(task_runner), db_(std::move(db)), - comparator_(std::move(comparator)), active_blob_registry_(this), committing_transaction_count_(0) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); @@ -594,9 +534,6 @@ for (const auto& pid : child_process_ids_granted_) policy->RevokeAllPermissionsForFile(pid, blob_path_); } - // db_'s destructor uses comparator_. The order of destruction is important. - db_.reset(); - comparator_.reset(); } IndexedDBBackingStore::RecordIdentifier::RecordIdentifier( @@ -615,123 +552,11 @@ constexpr const base::TimeDelta IndexedDBBackingStore::kInitialJournalCleaningWindowTime; -// static -scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( - IndexedDBFactory* indexed_db_factory, - const Origin& origin, - const FilePath& path_base, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - base::SequencedTaskRunner* task_runner, - bool clean_journal, - Status* status) { - DefaultLevelDBFactory leveldb_factory; - return IndexedDBBackingStore::Open( - indexed_db_factory, origin, path_base, data_loss_info, disk_full, - &leveldb_factory, task_runner, clean_journal, status); -} - -Status IndexedDBBackingStore::DestroyBackingStore(const FilePath& path_base, - const Origin& origin) { - const FilePath file_path = - path_base.Append(IndexedDBContextImpl::GetLevelDBFileName(origin)); - DefaultLevelDBFactory leveldb_factory; - return leveldb_factory.DestroyLevelDB(file_path); -} - -Status IndexedDBBackingStore::AnyDatabaseContainsBlobs( - LevelDBTransaction* transaction, - bool* blobs_exist) { +leveldb::Status IndexedDBBackingStore::Initialize(bool clean_live_journal) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); - - Status status = leveldb::Status::OK(); - std::vector<base::string16> names; - IndexedDBMetadataCoding metadata_coding; - status = metadata_coding.ReadDatabaseNames(transaction, origin_identifier_, - &names); - if (!status.ok()) - return status; - - *blobs_exist = false; - for (const auto& name : names) { - IndexedDBDatabaseMetadata metadata; - bool found = false; - status = metadata_coding.ReadMetadataForDatabaseName( - transaction, origin_identifier_, name, &metadata, &found); - if (!found) - return Status::NotFound("Metadata not found for \"%s\".", - base::UTF16ToUTF8(name)); - for (const auto& store_id_metadata_pair : metadata.object_stores) { - std::unique_ptr<LevelDBIterator> iterator = transaction->CreateIterator(); - std::string min_key = BlobEntryKey::EncodeMinKeyForObjectStore( - metadata.id, store_id_metadata_pair.first); - std::string max_key = BlobEntryKey::EncodeStopKeyForObjectStore( - metadata.id, store_id_metadata_pair.first); - status = iterator->Seek(base::StringPiece(min_key)); - if (status.IsNotFound()) { - status = Status::OK(); - continue; - } - if (!status.ok()) - return status; - if (iterator->IsValid() && - comparator_->Compare(iterator->Key(), base::StringPiece(max_key)) < - 0) { - *blobs_exist = true; - return Status::OK(); - } - } - - if (!status.ok()) - return status; - } - return Status::OK(); -} - -Status IndexedDBBackingStore::RevertSchemaToV2() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - const std::string schema_version_key = SchemaVersionKey::Encode(); - scoped_refptr<LevelDBTransaction> transaction = - IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); - - PutInt(transaction.get(), schema_version_key, 2); - Status s = transaction->Commit(); - if (!s.ok()) - INTERNAL_WRITE_ERROR_UNTESTED(REVERT_SCHEMA_TO_V2); - return s; -} - -V2SchemaCorruptionStatus IndexedDBBackingStore::HasV2SchemaCorruption() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - const std::string schema_version_key = SchemaVersionKey::Encode(); - scoped_refptr<LevelDBTransaction> transaction = - IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); - - int64_t db_schema_version = 0; - bool found = false; - Status s = - GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); - if (!s.ok()) - return V2SchemaCorruptionStatus::kUnknown; - if (db_schema_version != 2) - return V2SchemaCorruptionStatus::kNo; - - bool has_blobs = false; - s = AnyDatabaseContainsBlobs(transaction.get(), &has_blobs); - if (!s.ok()) - return V2SchemaCorruptionStatus::kUnknown; - if (!has_blobs) - return V2SchemaCorruptionStatus::kNo; - - s = transaction->Commit(); - if (!s.ok()) - return V2SchemaCorruptionStatus::kUnknown; - return V2SchemaCorruptionStatus::kYes; -} - -WARN_UNUSED_RESULT Status IndexedDBBackingStore::SetUpMetadata() { - DCHECK(task_runner_->RunsTasksInCurrentSequence()); - +#if DCHECK_IS_ON() + DCHECK(!initialized_); +#endif const IndexedDBDataFormatVersion latest_known_data_version = IndexedDBDataFormatVersion::GetCurrent(); const std::string schema_version_key = SchemaVersionKey::Encode(); @@ -746,7 +571,7 @@ Status s = GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); if (!s.ok()) { - INTERNAL_READ_ERROR_UNTESTED(SET_UP_METADATA); + INTERNAL_READ_ERROR(SET_UP_METADATA); return s; } indexed_db::ReportSchemaVersion(db_schema_version, origin_); @@ -867,14 +692,127 @@ DCHECK(db_data_version == latest_known_data_version); s = transaction->Commit(); - if (!s.ok()) + if (!s.ok()) { INTERNAL_WRITE_ERROR_UNTESTED(SET_UP_METADATA); + return s; + } + + if (clean_live_journal) + s = CleanUpBlobJournal(LiveBlobJournalKey::Encode()); + if (!s.ok()) { + indexed_db::ReportOpenStatus( + indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, + origin_); + return s; + } +#if DCHECK_IS_ON() + initialized_ = true; +#endif return s; } +Status IndexedDBBackingStore::AnyDatabaseContainsBlobs( + LevelDBTransaction* transaction, + bool* blobs_exist) { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); + + Status status = leveldb::Status::OK(); + std::vector<base::string16> names; + IndexedDBMetadataCoding metadata_coding; + status = metadata_coding.ReadDatabaseNames(transaction, origin_identifier_, + &names); + if (!status.ok()) + return status; + + *blobs_exist = false; + for (const auto& name : names) { + IndexedDBDatabaseMetadata metadata; + bool found = false; + status = metadata_coding.ReadMetadataForDatabaseName( + transaction, origin_identifier_, name, &metadata, &found); + if (!found) + return Status::NotFound("Metadata not found for \"%s\".", + base::UTF16ToUTF8(name)); + for (const auto& store_id_metadata_pair : metadata.object_stores) { + std::unique_ptr<LevelDBIterator> iterator = transaction->CreateIterator(); + std::string min_key = BlobEntryKey::EncodeMinKeyForObjectStore( + metadata.id, store_id_metadata_pair.first); + std::string max_key = BlobEntryKey::EncodeStopKeyForObjectStore( + metadata.id, store_id_metadata_pair.first); + status = iterator->Seek(base::StringPiece(min_key)); + if (status.IsNotFound()) { + status = Status::OK(); + continue; + } + if (!status.ok()) + return status; + if (iterator->IsValid() && + db()->Comparator()->Compare(iterator->Key(), + base::StringPiece(max_key)) < 0) { + *blobs_exist = true; + return Status::OK(); + } + } + + if (!status.ok()) + return status; + } + return Status::OK(); +} + +Status IndexedDBBackingStore::RevertSchemaToV2() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif + const std::string schema_version_key = SchemaVersionKey::Encode(); + scoped_refptr<LevelDBTransaction> transaction = + IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); + + PutInt(transaction.get(), schema_version_key, 2); + Status s = transaction->Commit(); + if (!s.ok()) + INTERNAL_WRITE_ERROR_UNTESTED(REVERT_SCHEMA_TO_V2); + return s; +} + +V2SchemaCorruptionStatus IndexedDBBackingStore::HasV2SchemaCorruption() { + DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif + const std::string schema_version_key = SchemaVersionKey::Encode(); + scoped_refptr<LevelDBTransaction> transaction = + IndexedDBClassFactory::Get()->CreateLevelDBTransaction(db_.get()); + + int64_t db_schema_version = 0; + bool found = false; + Status s = + GetInt(transaction.get(), schema_version_key, &db_schema_version, &found); + if (!s.ok()) + return V2SchemaCorruptionStatus::kUnknown; + if (db_schema_version != 2) + return V2SchemaCorruptionStatus::kNo; + + bool has_blobs = false; + s = AnyDatabaseContainsBlobs(transaction.get(), &has_blobs); + if (!s.ok()) + return V2SchemaCorruptionStatus::kUnknown; + if (!has_blobs) + return V2SchemaCorruptionStatus::kNo; + + s = transaction->Commit(); + if (!s.ok()) + return V2SchemaCorruptionStatus::kUnknown; + return V2SchemaCorruptionStatus::kYes; +} + leveldb::Status IndexedDBBackingStore::GetCompleteMetadata( std::vector<IndexedDBDatabaseMetadata>* output) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif IndexedDBMetadataCoding metadata_coding; leveldb::Status status = leveldb::Status::OK(); @@ -902,49 +840,11 @@ } // static -bool IndexedDBBackingStore::ReadCorruptionInfo(const FilePath& path_base, - const Origin& origin, - std::string* message) { - const FilePath info_path = - path_base.Append(ComputeCorruptionFileName(origin)); - - if (IsPathTooLong(info_path)) - return false; - - const int64_t kMaxJsonLength = 4096; - int64_t file_size = 0; - if (!GetFileSize(info_path, &file_size)) - return false; - if (!file_size || file_size > kMaxJsonLength) { - base::DeleteFile(info_path, false); - return false; - } - - base::File file(info_path, base::File::FLAG_OPEN | base::File::FLAG_READ); - bool success = false; - if (file.IsValid()) { - std::string input_js(file_size, '\0'); - if (file_size == file.Read(0, base::data(input_js), file_size)) { - base::JSONReader reader; - std::unique_ptr<base::DictionaryValue> val( - base::DictionaryValue::From(reader.ReadToValue(input_js))); - if (val) - success = val->GetString("message", message); - } - file.Close(); - } - - base::DeleteFile(info_path, false); - - return success; -} - -// static bool IndexedDBBackingStore::RecordCorruptionInfo(const FilePath& path_base, const Origin& origin, const std::string& message) { const FilePath info_path = - path_base.Append(ComputeCorruptionFileName(origin)); + path_base.Append(indexed_db::ComputeCorruptionFileName(origin)); if (IsPathTooLong(info_path)) return false; @@ -961,220 +861,6 @@ return size_t(written) == output_js.length(); } -// static -scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( - IndexedDBFactory* indexed_db_factory, - const Origin& origin, - const FilePath& path_base, - IndexedDBDataLossInfo* data_loss_info, - bool* is_disk_full, - LevelDBFactory* leveldb_factory, - base::SequencedTaskRunner* task_runner, - bool clean_journal, - Status* status) { - IDB_TRACE("IndexedDBBackingStore::Open"); - DCHECK(!path_base.empty()); - *is_disk_full = false; - - data_loss_info->status = blink::mojom::IDBDataLoss::None; - *status = Status::OK(); - - std::unique_ptr<LevelDBComparator> comparator(std::make_unique<Comparator>()); - - if (!base::IsStringASCII(path_base.AsUTF8Unsafe())) { - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_ATTEMPT_NON_ASCII, origin); - } - if (!base::CreateDirectory(path_base)) { - *status = Status::IOError("Unable to create IndexedDB database path"); - LOG(ERROR) << status->ToString() << ": \"" << path_base.AsUTF8Unsafe() - << "\""; - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, origin); - return scoped_refptr<IndexedDBBackingStore>(); - } - - const FilePath file_path = - path_base.Append(IndexedDBContextImpl::GetLevelDBFileName(origin)); - const FilePath blob_path = - path_base.Append(IndexedDBContextImpl::GetBlobStoreFileName(origin)); - - if (IsPathTooLong(file_path)) { - *status = Status::IOError("File path too long"); - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, origin); - return scoped_refptr<IndexedDBBackingStore>(); - } - - std::unique_ptr<LevelDBDatabase> db; - *status = leveldb_factory->OpenLevelDB( - file_path, comparator.get(), &db, is_disk_full); - - DCHECK(!db == !status->ok()); - if (!status->ok()) { - if (leveldb_env::IndicatesDiskFull(*status)) { - *is_disk_full = true; - } else if (status->IsCorruption()) { - data_loss_info->status = blink::mojom::IDBDataLoss::Total; - data_loss_info->message = leveldb_env::GetCorruptionMessage(*status); - } - } - - bool is_schema_known = false; - if (db) { - std::string corruption_message; - if (ReadCorruptionInfo(path_base, origin, &corruption_message)) { - LOG(ERROR) << "IndexedDB recovering from a corrupted (and deleted) " - "database."; - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, - origin); - db.reset(); - data_loss_info->status = blink::mojom::IDBDataLoss::Total; - data_loss_info->message = - "IndexedDB (database was corrupt): " + corruption_message; - } else if (!IsSchemaKnown(db.get(), &is_schema_known)) { - LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as " - "failure to open"; - HistogramOpenStatus( - indexed_db:: - INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, - origin); - db.reset(); - data_loss_info->status = blink::mojom::IDBDataLoss::Total; - data_loss_info->message = "I/O error checking schema"; - } else if (!is_schema_known) { - LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it " - "as failure to open"; - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, - origin); - db.reset(); - data_loss_info->status = blink::mojom::IDBDataLoss::Total; - data_loss_info->message = "Unknown schema"; - } - } - - DCHECK(status->ok() || !is_schema_known || status->IsIOError() || - status->IsCorruption()); - - if (db) { - HistogramOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, - origin); - } else if (status->IsIOError()) { - LOG(ERROR) << "Unable to open backing store, not trying to recover - " - << status->ToString(); - HistogramOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, - origin); - return scoped_refptr<IndexedDBBackingStore>(); - } else { - DCHECK(!is_schema_known || status->IsCorruption()); - LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup"; - *status = leveldb_factory->DestroyLevelDB(file_path); - if (!status->ok()) { - LOG(ERROR) << "IndexedDB backing store cleanup failed"; - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, - origin); - return scoped_refptr<IndexedDBBackingStore>(); - } - - LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening"; - *status = - leveldb_factory->OpenLevelDB(file_path, comparator.get(), &db, nullptr); - if (!status->ok()) { - DCHECK(!db); - LOG(ERROR) << "IndexedDB backing store reopen after recovery failed"; - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, - origin); - return scoped_refptr<IndexedDBBackingStore>(); - } - HistogramOpenStatus( - indexed_db::INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, - origin); - } - - base::trace_event::MemoryDumpManager::GetInstance() - ->RegisterDumpProviderWithSequencedTaskRunner( - db.get(), "IndexedDBBackingStore", task_runner, - base::trace_event::MemoryDumpProvider::Options()); - - scoped_refptr<IndexedDBBackingStore> backing_store = - Create(indexed_db_factory, origin, blob_path, std::move(db), - std::move(comparator), task_runner, status); - - if (clean_journal && backing_store.get()) { - *status = backing_store->CleanUpBlobJournal(LiveBlobJournalKey::Encode()); - if (!status->ok()) { - HistogramOpenStatus( - indexed_db:: - INDEXED_DB_BACKING_STORE_OPEN_FAILED_CLEANUP_JOURNAL_ERROR, - origin); - return scoped_refptr<IndexedDBBackingStore>(); - } - } - return backing_store; -} - -// static -scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( - const Origin& origin, - base::SequencedTaskRunner* task_runner, - Status* status) { - DefaultLevelDBFactory leveldb_factory; - return IndexedDBBackingStore::OpenInMemory(origin, &leveldb_factory, - task_runner, status); -} - -// static -scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( - const Origin& origin, - LevelDBFactory* leveldb_factory, - base::SequencedTaskRunner* task_runner, - Status* status) { - IDB_TRACE("IndexedDBBackingStore::OpenInMemory"); - - std::unique_ptr<LevelDBComparator> comparator(std::make_unique<Comparator>()); - std::unique_ptr<LevelDBDatabase> db = - LevelDBDatabase::OpenInMemory(comparator.get()); - if (!db) { - LOG(ERROR) << "LevelDBDatabase::OpenInMemory failed."; - HistogramOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_MEMORY_FAILED, - origin); - return scoped_refptr<IndexedDBBackingStore>(); - } - HistogramOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_MEMORY_SUCCESS, - origin); - base::trace_event::MemoryDumpManager::GetInstance() - ->RegisterDumpProviderWithSequencedTaskRunner( - db.get(), "IndexedDBBackingStore", task_runner, - base::trace_event::MemoryDumpProvider::Options()); - - return Create(nullptr /* indexed_db_factory */, origin, FilePath(), - std::move(db), std::move(comparator), task_runner, status); -} - -// static -scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( - IndexedDBFactory* indexed_db_factory, - const Origin& origin, - const FilePath& blob_path, - std::unique_ptr<LevelDBDatabase> db, - std::unique_ptr<LevelDBComparator> comparator, - base::SequencedTaskRunner* task_runner, - Status* status) { - // TODO(jsbell): Handle comparator name changes. - scoped_refptr<IndexedDBBackingStore> backing_store(new IndexedDBBackingStore( - indexed_db_factory, origin, blob_path, std::move(db), - std::move(comparator), task_runner)); - *status = backing_store->SetUpMetadata(); - if (!status->ok()) - return scoped_refptr<IndexedDBBackingStore>(); - - return backing_store; -} - void IndexedDBBackingStore::GrantChildProcessPermissions(int child_process_id) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); @@ -1187,6 +873,9 @@ Status IndexedDBBackingStore::DeleteDatabase(const base::string16& name) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif IDB_TRACE("IndexedDBBackingStore::DeleteDatabase"); std::unique_ptr<LevelDBDirectTransaction> transaction = @@ -1255,6 +944,9 @@ void IndexedDBBackingStore::Compact() { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif db_->CompactAll(); } @@ -1265,6 +957,9 @@ const IndexedDBKey& key, IndexedDBValue* record) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif IDB_TRACE("IndexedDBBackingStore::GetRecord"); if (!KeyPrefix::ValidIds(database_id, object_store_id)) @@ -1323,6 +1018,9 @@ IndexedDBValue* value, RecordIdentifier* record_identifier) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif IDB_TRACE("IndexedDBBackingStore::PutRecord"); if (!KeyPrefix::ValidIds(database_id, object_store_id)) @@ -1366,6 +1064,9 @@ int64_t database_id, int64_t object_store_id) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif IDB_TRACE("IndexedDBBackingStore::ClearObjectStore"); if (!KeyPrefix::ValidIds(database_id, object_store_id)) @@ -1414,6 +1115,9 @@ int64_t object_store_id, const IndexedDBKeyRange& key_range) { DCHECK(task_runner_->RunsTasksInCurrentSequence()); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif Status s; std::unique_ptr<IndexedDBBackingStore::Cursor> start_cursor = @@ -1467,6 +1171,9 @@ int64_t database_id, int64_t object_store_id, int64_t* key_generator_current_number) { +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif if (!KeyPrefix::ValidIds(database_id, object_store_id)) return InvalidDBKeyStatus(); LevelDBTransaction* leveldb_transaction = transaction->transaction(); @@ -1539,6 +1246,9 @@ int64_t object_store_id, int64_t new_number, bool check_current) { +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif if (!KeyPrefix::ValidIds(database_id, object_store_id)) return InvalidDBKeyStatus(); @@ -1568,6 +1278,9 @@ const IndexedDBKey& key, RecordIdentifier* found_record_identifier, bool* found) { +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif IDB_TRACE("IndexedDBBackingStore::KeyExistsInObjectStore"); if (!KeyPrefix::ValidIds(database_id, object_store_id)) return InvalidDBKeyStatus(); @@ -1809,6 +1522,9 @@ int64_t database_id, const Transaction::WriteDescriptor& descriptor, Transaction::ChainedBlobWriter* chained_blob_writer) { +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key())) return false; @@ -1857,6 +1573,9 @@ void IndexedDBBackingStore::ReportBlobUnused(int64_t database_id, int64_t blob_key) { DCHECK(KeyPrefix::IsValidDatabaseId(database_id)); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif bool all_blobs = blob_key == DatabaseMetaDataKey::kAllBlobsKey; DCHECK(all_blobs || DatabaseMetaDataKey::IsValidBlobKey(blob_key)); scoped_refptr<LevelDBTransaction> transaction = @@ -1920,6 +1639,9 @@ // HasLastBackingStoreReference. It's safe because if the backing store is // deleted, the timer will automatically be canceled on destruction. void IndexedDBBackingStore::StartJournalCleaningTimer() { +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif ++num_aggregated_journal_cleaning_requests_; if (execute_journal_cleaning_on_no_txns_) @@ -2114,6 +1836,9 @@ int64_t object_store_id, int64_t index_id) { IDB_TRACE("IndexedDBBackingStore::ClearIndex"); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) return InvalidDBKeyStatus(); LevelDBTransaction* leveldb_transaction = transaction->transaction(); @@ -2139,6 +1864,9 @@ const IndexedDBKey& key, const RecordIdentifier& record_identifier) { IDB_TRACE("IndexedDBBackingStore::PutIndexDataForRecord"); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif DCHECK(key.IsValid()); if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) return InvalidDBKeyStatus(); @@ -2171,6 +1899,9 @@ std::string* found_encoded_primary_key, bool* found) { IDB_TRACE("IndexedDBBackingStore::FindKeyInIndex"); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif DCHECK(KeyPrefix::ValidIds(database_id, object_store_id, index_id)); DCHECK(found_encoded_primary_key->empty()); @@ -2226,6 +1957,9 @@ const IndexedDBKey& key, std::unique_ptr<IndexedDBKey>* primary_key) { IDB_TRACE("IndexedDBBackingStore::GetPrimaryKeyViaIndex"); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) return InvalidDBKeyStatus(); @@ -2260,6 +1994,9 @@ std::unique_ptr<IndexedDBKey>* found_primary_key, bool* exists) { IDB_TRACE("IndexedDBBackingStore::KeyExistsInIndex"); +#if DCHECK_IS_ON() + DCHECK(initialized_); +#endif if (!KeyPrefix::ValidIds(database_id, object_store_id, index_id)) return InvalidDBKeyStatus();
diff --git a/content/browser/indexed_db/indexed_db_backing_store.h b/content/browser/indexed_db/indexed_db_backing_store.h index 3646a91..1f5f3ee4 100644 --- a/content/browser/indexed_db/indexed_db_backing_store.h +++ b/content/browser/indexed_db/indexed_db_backing_store.h
@@ -56,8 +56,6 @@ class IndexedDBFactory; class LevelDBComparator; class LevelDBDatabase; -class LevelDBFactory; -struct IndexedDBDataLossInfo; struct IndexedDBValue; namespace indexed_db_backing_store_unittest { @@ -71,6 +69,8 @@ kYes = 2, }; +// All interaction with this class should be done on the task runner given to +// Open. class CONTENT_EXPORT IndexedDBBackingStore : public base::RefCounted<IndexedDBBackingStore> { public: @@ -391,6 +391,16 @@ static constexpr const base::TimeDelta kInitialJournalCleaningWindowTime = base::TimeDelta::FromSeconds(2); + IndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, + const url::Origin& origin, + const base::FilePath& blob_path, + std::unique_ptr<LevelDBDatabase> db, + base::SequencedTaskRunner* task_runner); + + // Initializes the backing store. This must be called before doing any + // operations or method calls on this object. + leveldb::Status Initialize(bool clean_live_blob_journal); + const url::Origin& origin() const { return origin_; } IndexedDBFactory* factory() const { return indexed_db_factory_; } base::SequencedTaskRunner* task_runner() const { return task_runner_.get(); } @@ -399,44 +409,12 @@ return &active_blob_registry_; } - static scoped_refptr<IndexedDBBackingStore> Open( - IndexedDBFactory* indexed_db_factory, - const url::Origin& origin, - const base::FilePath& path_base, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - base::SequencedTaskRunner* task_runner, - bool clean_journal, - leveldb::Status* status); - static scoped_refptr<IndexedDBBackingStore> Open( - IndexedDBFactory* indexed_db_factory, - const url::Origin& origin, - const base::FilePath& path_base, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - LevelDBFactory* leveldb_factory, - base::SequencedTaskRunner* task_runner, - bool clean_journal, - leveldb::Status* status); - static scoped_refptr<IndexedDBBackingStore> OpenInMemory( - const url::Origin& origin, - base::SequencedTaskRunner* task_runner, - leveldb::Status* status); - static scoped_refptr<IndexedDBBackingStore> OpenInMemory( - const url::Origin& origin, - LevelDBFactory* leveldb_factory, - base::SequencedTaskRunner* task_runner, - leveldb::Status* status); - void GrantChildProcessPermissions(int child_process_id); // Compact is public for testing. virtual void Compact(); virtual leveldb::Status DeleteDatabase(const base::string16& name); - // Assumes caller has already closed the backing store. - static leveldb::Status DestroyBackingStore(const base::FilePath& path_base, - const url::Origin& origin); static bool RecordCorruptionInfo(const base::FilePath& path_base, const url::Origin& origin, const std::string& message); @@ -592,14 +570,6 @@ protected: friend class base::RefCounted<IndexedDBBackingStore>; - - IndexedDBBackingStore( - IndexedDBFactory* indexed_db_factory, - const url::Origin& origin, - const base::FilePath& blob_path, - std::unique_ptr<LevelDBDatabase> db, - std::unique_ptr<LevelDBComparator> comparator, - base::SequencedTaskRunner* task_runner); virtual ~IndexedDBBackingStore(); bool is_incognito() const { return !indexed_db_factory_; } @@ -607,8 +577,6 @@ leveldb::Status AnyDatabaseContainsBlobs(LevelDBTransaction* transaction, bool* blobs_exist); - leveldb::Status SetUpMetadata(); - // TODO(dmurph): Move this completely to IndexedDBMetadataFactory. leveldb::Status GetCompleteMetadata( std::vector<blink::IndexedDBDatabaseMetadata>* output); @@ -633,23 +601,6 @@ void CleanPrimaryJournalIgnoreReturn(); private: - FRIEND_TEST_ALL_PREFIXES( - indexed_db_backing_store_unittest::IndexedDBBackingStoreTest, - ReadCorruptionInfo); - - static scoped_refptr<IndexedDBBackingStore> Create( - IndexedDBFactory* indexed_db_factory, - const url::Origin& origin, - const base::FilePath& blob_path, - std::unique_ptr<LevelDBDatabase> db, - std::unique_ptr<LevelDBComparator> comparator, - base::SequencedTaskRunner* task_runner, - leveldb::Status* status); - - static bool ReadCorruptionInfo(const base::FilePath& path_base, - const url::Origin& origin, - std::string* message); - leveldb::Status FindKeyInIndex( IndexedDBBackingStore::Transaction* transaction, int64_t database_id, @@ -704,9 +655,8 @@ #endif std::unique_ptr<LevelDBDatabase> db_; - std::unique_ptr<LevelDBComparator> comparator_; - // Whenever blobs are registered in active_blob_registry_, indexed_db_factory_ - // will hold a reference to this backing store. + // Whenever blobs are registered in active_blob_registry_, + // indexed_db_factory_ will hold a reference to this backing store. IndexedDBActiveBlobRegistry active_blob_registry_; base::OneShotTimer close_timer_; std::unique_ptr<IndexedDBPreCloseTaskQueue> pre_close_task_queue_; @@ -715,7 +665,9 @@ // complete. While > 0, temporary journal entries may exist so out-of-band // journal cleaning must be deferred. size_t committing_transaction_count_; - +#if DCHECK_IS_ON() + bool initialized_ = false; +#endif DISALLOW_COPY_AND_ASSIGN(IndexedDBBackingStore); };
diff --git a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc index 5ac3c10..a09b20b 100644 --- a/content/browser/indexed_db/indexed_db_backing_store_unittest.cc +++ b/content/browser/indexed_db/indexed_db_backing_store_unittest.cc
@@ -27,7 +27,6 @@ #include "content/browser/indexed_db/indexed_db_leveldb_operations.h" #include "content/browser/indexed_db/indexed_db_metadata_coding.h" #include "content/browser/indexed_db/indexed_db_value.h" -#include "content/browser/indexed_db/leveldb/leveldb_factory.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_utils.h" @@ -52,84 +51,25 @@ namespace content { namespace indexed_db_backing_store_unittest { -static const size_t kDefaultMaxOpenIteratorsPerDatabase = 50; - // Write |content| to |file|. Returns true on success. bool WriteFile(const base::FilePath& file, base::StringPiece content) { int write_size = base::WriteFile(file, content.data(), content.length()); return write_size >= 0 && write_size == static_cast<int>(content.length()); } -class Comparator : public LevelDBComparator { - public: - int Compare(const base::StringPiece& a, - const base::StringPiece& b) const override { - return content::Compare(a, b, false /*index_keys*/); - } - const char* Name() const override { return "idb_cmp1"; } -}; - -class DefaultLevelDBFactory : public LevelDBFactory { - public: - DefaultLevelDBFactory() {} - - leveldb::Status OpenLevelDB(const base::FilePath& file_name, - const LevelDBComparator* comparator, - std::unique_ptr<LevelDBDatabase>* db, - bool* is_disk_full) override { - return LevelDBDatabase::Open(file_name, comparator, - kDefaultMaxOpenIteratorsPerDatabase, db, - is_disk_full); - } - leveldb::Status DestroyLevelDB(const base::FilePath& file_name) override { - return LevelDBDatabase::Destroy(file_name); - } - - private: - DISALLOW_COPY_AND_ASSIGN(DefaultLevelDBFactory); -}; - class TestableIndexedDBBackingStore : public IndexedDBBackingStore { public: - static scoped_refptr<TestableIndexedDBBackingStore> Open( - IndexedDBFactory* indexed_db_factory, - const Origin& origin, - const base::FilePath& path_base, - LevelDBFactory* leveldb_factory, - base::SequencedTaskRunner* task_runner, - leveldb::Status* status) { - DCHECK(!path_base.empty()); - - std::unique_ptr<LevelDBComparator> comparator = - std::make_unique<Comparator>(); - - if (!base::CreateDirectory(path_base)) { - *status = leveldb::Status::IOError("Unable to create base dir"); - return scoped_refptr<TestableIndexedDBBackingStore>(); - } - - const base::FilePath file_path = path_base.AppendASCII("test_db_path"); - const base::FilePath blob_path = path_base.AppendASCII("test_blob_path"); - - std::unique_ptr<LevelDBDatabase> db; - bool is_disk_full = false; - *status = leveldb_factory->OpenLevelDB(file_path, comparator.get(), &db, - &is_disk_full); - - if (!db || !status->ok()) - return scoped_refptr<TestableIndexedDBBackingStore>(); - - scoped_refptr<TestableIndexedDBBackingStore> backing_store( - new TestableIndexedDBBackingStore(indexed_db_factory, origin, blob_path, - std::move(db), std::move(comparator), - task_runner)); - - *status = backing_store->SetUpMetadata(); - if (!status->ok()) - return scoped_refptr<TestableIndexedDBBackingStore>(); - - return backing_store; - } + TestableIndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, + const url::Origin& origin, + const base::FilePath& blob_path, + std::unique_ptr<LevelDBDatabase> db, + base::SequencedTaskRunner* task_runner) + : IndexedDBBackingStore(indexed_db_factory, + origin, + blob_path, + std::move(db), + task_runner), + database_id_(0) {} const std::vector<IndexedDBBackingStore::Transaction::WriteDescriptor>& writes() const { @@ -175,20 +115,6 @@ } private: - TestableIndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, - const Origin& origin, - const base::FilePath& blob_path, - std::unique_ptr<LevelDBDatabase> db, - std::unique_ptr<LevelDBComparator> comparator, - base::SequencedTaskRunner* task_runner) - : IndexedDBBackingStore(indexed_db_factory, - origin, - blob_path, - std::move(db), - std::move(comparator), - task_runner), - database_id_(0) {} - int64_t database_id_; std::vector<Transaction::WriteDescriptor> writes_; @@ -202,15 +128,18 @@ class TestIDBFactory : public IndexedDBFactoryImpl { public: explicit TestIDBFactory(IndexedDBContextImpl* idb_context) - : IndexedDBFactoryImpl(idb_context, base::DefaultClock::GetInstance()) {} + : IndexedDBFactoryImpl(idb_context, + indexed_db::GetDefaultLevelDBFactory(), + base::DefaultClock::GetInstance()) {} scoped_refptr<TestableIndexedDBBackingStore> OpenBackingStoreForTest( const Origin& origin) { IndexedDBDataLossInfo data_loss_info; bool disk_full; - leveldb::Status status; - auto backing_store = OpenBackingStore(origin, context()->data_path(), - &data_loss_info, &disk_full, &status); + leveldb::Status s; + scoped_refptr<IndexedDBBackingStore> backing_store; + std::tie(backing_store, s, data_loss_info, disk_full) = + OpenBackingStore(origin, context()->data_path()); scoped_refptr<TestableIndexedDBBackingStore> testable_store = static_cast<TestableIndexedDBBackingStore*>(backing_store.get()); return testable_store; @@ -219,17 +148,13 @@ protected: ~TestIDBFactory() override {} - scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( - const Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - bool first_time, - leveldb::Status* status) override { - DefaultLevelDBFactory leveldb_factory; - return TestableIndexedDBBackingStore::Open(this, origin, data_directory, - &leveldb_factory, - context()->TaskRunner(), status); + scoped_refptr<IndexedDBBackingStore> CreateBackingStore( + const url::Origin& origin, + const base::FilePath& blob_path, + std::unique_ptr<LevelDBDatabase> db, + base::SequencedTaskRunner* task_runner) override { + return base::MakeRefCounted<TestableIndexedDBBackingStore>( + this, origin, blob_path, std::move(db), task_runner); } private: @@ -275,7 +200,8 @@ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); idb_context_ = base::MakeRefCounted<IndexedDBContextImpl>( - temp_dir_.GetPath(), special_storage_policy_, quota_manager_proxy_); + temp_dir_.GetPath(), special_storage_policy_, quota_manager_proxy_, + indexed_db::GetDefaultLevelDBFactory()); CreateFactoryAndBackingStore(); @@ -446,6 +372,7 @@ called = true; switch (result) { case IndexedDBBackingStore::BlobWriteResult::FAILURE_ASYNC: + // Not tested. succeeded = false; break; case IndexedDBBackingStore::BlobWriteResult::SUCCESS_ASYNC: @@ -1266,11 +1193,8 @@ TEST_F(IndexedDBBackingStoreTest, ReadCorruptionInfo) { // No |path_base|. - std::string message; - EXPECT_FALSE(IndexedDBBackingStore::ReadCorruptionInfo(base::FilePath(), - Origin(), &message)); - EXPECT_TRUE(message.empty()); - message.clear(); + EXPECT_TRUE( + indexed_db::ReadCorruptionInfo(base::FilePath(), Origin()).empty()); const base::FilePath path_base = temp_dir_.GetPath(); const Origin origin = Origin::Create(GURL("http://www.google.com/")); @@ -1278,10 +1202,7 @@ ASSERT_TRUE(PathIsWritable(path_base)); // File not found. - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); - EXPECT_TRUE(message.empty()); - message.clear(); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); const base::FilePath info_path = path_base.AppendASCII("http_www.google.com_0.indexeddb.leveldb") @@ -1291,65 +1212,46 @@ // Empty file. std::string dummy_data; ASSERT_TRUE(WriteFile(info_path, dummy_data)); - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); EXPECT_FALSE(PathExists(info_path)); - EXPECT_TRUE(message.empty()); - message.clear(); // File size > 4 KB. dummy_data.resize(5000, 'c'); ASSERT_TRUE(WriteFile(info_path, dummy_data)); - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); EXPECT_FALSE(PathExists(info_path)); - EXPECT_TRUE(message.empty()); - message.clear(); // Random string. ASSERT_TRUE(WriteFile(info_path, "foo bar")); - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); EXPECT_FALSE(PathExists(info_path)); - EXPECT_TRUE(message.empty()); - message.clear(); // Not a dictionary. ASSERT_TRUE(WriteFile(info_path, "[]")); - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); EXPECT_FALSE(PathExists(info_path)); - EXPECT_TRUE(message.empty()); - message.clear(); // Empty dictionary. ASSERT_TRUE(WriteFile(info_path, "{}")); - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); EXPECT_FALSE(PathExists(info_path)); - EXPECT_TRUE(message.empty()); - message.clear(); // Dictionary, no message key. ASSERT_TRUE(WriteFile(info_path, "{\"foo\":\"bar\"}")); - EXPECT_FALSE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + EXPECT_TRUE(indexed_db::ReadCorruptionInfo(path_base, origin).empty()); EXPECT_FALSE(PathExists(info_path)); - EXPECT_TRUE(message.empty()); - message.clear(); // Dictionary, message key. ASSERT_TRUE(WriteFile(info_path, "{\"message\":\"bar\"}")); - EXPECT_TRUE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + std::string message = indexed_db::ReadCorruptionInfo(path_base, origin); + EXPECT_FALSE(message.empty()); EXPECT_FALSE(PathExists(info_path)); EXPECT_EQ("bar", message); - message.clear(); // Dictionary, message key and more. ASSERT_TRUE(WriteFile(info_path, "{\"message\":\"foo\",\"bar\":5}")); - EXPECT_TRUE( - IndexedDBBackingStore::ReadCorruptionInfo(path_base, origin, &message)); + message = indexed_db::ReadCorruptionInfo(path_base, origin); + EXPECT_FALSE(message.empty()); EXPECT_FALSE(PathExists(info_path)); EXPECT_EQ("foo", message); }
diff --git a/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc b/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc index 5f730766..4a1e27b 100644 --- a/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc +++ b/content/browser/indexed_db/indexed_db_cleanup_on_io_error_unittest.cc
@@ -3,168 +3,85 @@ // found in the LICENSE file. #include <cerrno> +#include <memory> #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "content/browser/indexed_db/indexed_db_backing_store.h" -#include "content/browser/indexed_db/indexed_db_data_loss_info.h" +#include "content/browser/indexed_db/leveldb/fake_leveldb_factory.h" #include "content/browser/indexed_db/leveldb/leveldb_database.h" -#include "content/browser/indexed_db/leveldb/mock_leveldb_factory.h" -#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/env_chromium.h" using base::StringPiece; -using content::IndexedDBBackingStore; -using content::LevelDBComparator; -using content::LevelDBDatabase; -using content::LevelDBFactory; -using content::LevelDBSnapshot; -using testing::_; -using testing::Exactly; -using testing::Invoke; namespace base { class TaskRunner; } namespace content { -class IndexedDBFactory; -} - namespace { -class BustedLevelDBDatabase : public LevelDBDatabase { - public: - BustedLevelDBDatabase() - : LevelDBDatabase(LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase) {} - static std::unique_ptr<LevelDBDatabase> Open( - const base::FilePath& file_name, - const LevelDBComparator* /*comparator*/) { - return std::make_unique<BustedLevelDBDatabase>(); - } - leveldb::Status Get(const base::StringPiece& key, - std::string* value, - bool* found, - const LevelDBSnapshot* = nullptr) override { - return leveldb::Status::IOError("It's busted!"); - } - - private: - DISALLOW_COPY_AND_ASSIGN(BustedLevelDBDatabase); -}; - -class BustedLevelDBFactory : public LevelDBFactory { - public: - leveldb::Status OpenLevelDB(const base::FilePath& file_name, - const LevelDBComparator* comparator, - std::unique_ptr<LevelDBDatabase>* db, - bool* is_disk_full = nullptr) override { - if (open_error_.ok()) - *db = BustedLevelDBDatabase::Open(file_name, comparator); - return open_error_; - } - leveldb::Status DestroyLevelDB(const base::FilePath& file_name) override { - return leveldb::Status::IOError("error"); - } - void SetOpenError(const leveldb::Status& open_error) { - open_error_ = open_error; - } - - private: - leveldb::Status open_error_; -}; - TEST(IndexedDBIOErrorTest, CleanUpTest) { - content::IndexedDBFactory* factory = nullptr; + base::test::ScopedTaskEnvironment task_env; const url::Origin origin = url::Origin::Create(GURL("http://localhost:81")); base::ScopedTempDir temp_directory; ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); const base::FilePath path = temp_directory.GetPath(); - BustedLevelDBFactory busted_factory; - content::MockLevelDBFactory mock_leveldb_factory; - ON_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).WillByDefault( - Invoke(&busted_factory, &BustedLevelDBFactory::OpenLevelDB)); - ON_CALL(mock_leveldb_factory, DestroyLevelDB(_)).WillByDefault( - Invoke(&busted_factory, &BustedLevelDBFactory::DestroyLevelDB)); - - EXPECT_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).Times(Exactly(1)); - EXPECT_CALL(mock_leveldb_factory, DestroyLevelDB(_)).Times(Exactly(1)); - content::IndexedDBDataLossInfo data_loss_info; - bool disk_full = false; - base::SequencedTaskRunner* task_runner = nullptr; - bool clean_journal = false; - leveldb::Status s; + auto task_runner = base::SequencedTaskRunnerHandle::Get(); scoped_refptr<IndexedDBBackingStore> backing_store = - IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info, - &disk_full, &mock_leveldb_factory, - task_runner, clean_journal, &s); + base::MakeRefCounted<IndexedDBBackingStore>( + nullptr, origin, path, + std::make_unique<LevelDBDatabase>( + indexed_db::FakeLevelDBFactory::GetBrokenLevelDB( + leveldb::Status::IOError("It's broken!"), path), + task_runner.get(), + LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase), + task_runner.get()); + leveldb::Status s = backing_store->Initialize(false); + EXPECT_FALSE(s.ok()); } TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { - content::IndexedDBFactory* factory = nullptr; + base::test::ScopedTaskEnvironment task_env; const url::Origin origin = url::Origin::Create(GURL("http://localhost:81")); base::ScopedTempDir temp_directory; ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); const base::FilePath path = temp_directory.GetPath(); - content::IndexedDBDataLossInfo data_loss_info; - bool disk_full = false; - base::SequencedTaskRunner* task_runner = nullptr; - bool clean_journal = false; + auto task_runner = base::SequencedTaskRunnerHandle::Get(); leveldb::Status s; - BustedLevelDBFactory busted_factory; - content::MockLevelDBFactory mock_leveldb_factory; - ON_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).WillByDefault( - Invoke(&busted_factory, &BustedLevelDBFactory::OpenLevelDB)); - ON_CALL(mock_leveldb_factory, DestroyLevelDB(_)).WillByDefault( - Invoke(&busted_factory, &BustedLevelDBFactory::DestroyLevelDB)); - - EXPECT_CALL(mock_leveldb_factory, OpenLevelDB(_, _, _, _)).Times(Exactly(4)); - EXPECT_CALL(mock_leveldb_factory, DestroyLevelDB(_)).Times(Exactly(0)); - - busted_factory.SetOpenError(MakeIOError("some filename", "some message", - leveldb_env::kNewLogger, - base::File::FILE_ERROR_NO_SPACE)); - scoped_refptr<IndexedDBBackingStore> backing_store = - IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info, - &disk_full, &mock_leveldb_factory, - task_runner, clean_journal, &s); - ASSERT_TRUE(s.IsIOError()); - - busted_factory.SetOpenError(MakeIOError("some filename", - "some message", - leveldb_env::kNewLogger, - base::File::FILE_ERROR_NO_MEMORY)); - scoped_refptr<IndexedDBBackingStore> backing_store2 = - IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info, - &disk_full, &mock_leveldb_factory, - task_runner, clean_journal, &s); - ASSERT_TRUE(s.IsIOError()); - - busted_factory.SetOpenError(MakeIOError("some filename", "some message", - leveldb_env::kNewLogger, - base::File::FILE_ERROR_IO)); - scoped_refptr<IndexedDBBackingStore> backing_store3 = - IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info, - &disk_full, &mock_leveldb_factory, - task_runner, clean_journal, &s); - ASSERT_TRUE(s.IsIOError()); - - busted_factory.SetOpenError(MakeIOError("some filename", - "some message", - leveldb_env::kNewLogger, - base::File::FILE_ERROR_FAILED)); - scoped_refptr<IndexedDBBackingStore> backing_store4 = - IndexedDBBackingStore::Open(factory, origin, path, &data_loss_info, - &disk_full, &mock_leveldb_factory, - task_runner, clean_journal, &s); - ASSERT_TRUE(s.IsIOError()); + std::array<leveldb::Status, 4> errors = { + MakeIOError("some filename", "some message", leveldb_env::kNewLogger, + base::File::FILE_ERROR_NO_SPACE), + MakeIOError("some filename", "some message", leveldb_env::kNewLogger, + base::File::FILE_ERROR_NO_MEMORY), + MakeIOError("some filename", "some message", leveldb_env::kNewLogger, + base::File::FILE_ERROR_IO), + MakeIOError("some filename", "some message", leveldb_env::kNewLogger, + base::File::FILE_ERROR_FAILED)}; + for (leveldb::Status error_status : errors) { + scoped_refptr<IndexedDBBackingStore> backing_store = + base::MakeRefCounted<IndexedDBBackingStore>( + nullptr, origin, path, + std::make_unique<LevelDBDatabase>( + indexed_db::FakeLevelDBFactory::GetBrokenLevelDB(error_status, + path), + task_runner.get(), + LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase), + task_runner.get()); + leveldb::Status s = backing_store->Initialize(false); + ASSERT_TRUE(s.IsIOError()); + } } } // namespace +} // namespace content
diff --git a/content/browser/indexed_db/indexed_db_context_impl.cc b/content/browser/indexed_db/indexed_db_context_impl.cc index cd6dd1eb..7cf3cb14c 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.cc +++ b/content/browser/indexed_db/indexed_db_context_impl.cc
@@ -27,9 +27,11 @@ #include "content/browser/indexed_db/indexed_db_database.h" #include "content/browser/indexed_db/indexed_db_dispatcher_host.h" #include "content/browser/indexed_db/indexed_db_factory_impl.h" +#include "content/browser/indexed_db/indexed_db_leveldb_operations.h" #include "content/browser/indexed_db/indexed_db_quota_client.h" #include "content/browser/indexed_db/indexed_db_tracing.h" #include "content/browser/indexed_db/indexed_db_transaction.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/storage_usage_info.h" #include "content/public/common/content_switches.h" @@ -49,15 +51,6 @@ const base::FilePath::CharType IndexedDBContextImpl::kIndexedDBDirectory[] = FILE_PATH_LITERAL("IndexedDB"); -static const base::FilePath::CharType kBlobExtension[] = - FILE_PATH_LITERAL(".blob"); - -static const base::FilePath::CharType kIndexedDBExtension[] = - FILE_PATH_LITERAL(".indexeddb"); - -static const base::FilePath::CharType kLevelDBExtension[] = - FILE_PATH_LITERAL(".leveldb"); - namespace { // This may be called after the IndexedDBContext is destroyed. @@ -68,14 +61,18 @@ // if a global handle to it is ever available. if (indexeddb_path.empty()) return; - base::FileEnumerator file_enumerator( - indexeddb_path, false, base::FileEnumerator::DIRECTORIES); + base::FileEnumerator file_enumerator(indexeddb_path, false, + base::FileEnumerator::DIRECTORIES); for (base::FilePath file_path = file_enumerator.Next(); !file_path.empty(); file_path = file_enumerator.Next()) { - if (file_path.Extension() == kLevelDBExtension && - file_path.RemoveExtension().Extension() == kIndexedDBExtension) { - std::string origin_id = file_path.BaseName().RemoveExtension() - .RemoveExtension().MaybeAsASCII(); + if (file_path.Extension() == indexed_db::kLevelDBExtension && + file_path.RemoveExtension().Extension() == + indexed_db::kIndexedDBExtension) { + // TODO(dmurph): Unittest this. + std::string origin_id = file_path.BaseName() + .RemoveExtension() + .RemoveExtension() + .MaybeAsASCII(); origins->push_back(storage::GetOriginFromIdentifier(origin_id)); if (file_paths) file_paths->push_back(file_path); @@ -88,7 +85,8 @@ IndexedDBContextImpl::IndexedDBContextImpl( const base::FilePath& data_path, scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + indexed_db::LevelDBFactory* leveldb_factory) : force_keep_session_state_(false), special_storage_policy_(special_storage_policy), quota_manager_proxy_(quota_manager_proxy), @@ -96,7 +94,8 @@ {base::MayBlock(), base::WithBaseSyncPrimitives(), base::TaskPriority::USER_VISIBLE, // BLOCK_SHUTDOWN to support clearing session-only storage. - base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) { + base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), + leveldb_factory_(leveldb_factory) { IDB_TRACE("init"); if (!data_path.empty()) data_path_ = data_path.Append(kIndexedDBDirectory); @@ -105,14 +104,14 @@ IndexedDBFactory* IndexedDBContextImpl::GetIDBFactory() { DCHECK(TaskRunner()->RunsTasksInCurrentSequence()); - if (!factory_.get()) { + if (!indexeddb_factory_.get()) { // Prime our cache of origins with existing databases so we can // detect when dbs are newly created. GetOriginSet(); - factory_ = - new IndexedDBFactoryImpl(this, base::DefaultClock::GetInstance()); + indexeddb_factory_ = base::MakeRefCounted<IndexedDBFactoryImpl>( + this, leveldb_factory_, base::DefaultClock::GetInstance()); } - return factory_.get(); + return indexeddb_factory_.get(); } std::vector<Origin> IndexedDBContextImpl::GetAllOrigins() { @@ -170,10 +169,10 @@ // to extract just those in the origin, and we're iterating over all // origins in the outer loop. - if (factory_.get()) { + if (indexeddb_factory_.get()) { std::pair<IndexedDBFactory::OriginDBMapIterator, IndexedDBFactory::OriginDBMapIterator> - range = factory_->GetOpenDatabasesForOrigin(origin); + range = indexeddb_factory_->GetOpenDatabasesForOrigin(origin); // TODO(jsbell): Sort by name? std::unique_ptr<base::ListValue> database_list( std::make_unique<base::ListValue>()); @@ -292,9 +291,9 @@ return base::Time(); if (is_incognito()) { - if (!factory_) + if (!indexeddb_factory_) return base::Time(); - return factory_->GetLastModified(origin); + return indexeddb_factory_->GetLastModified(origin); } base::FilePath idb_directory = GetLevelDBPath(origin); @@ -318,7 +317,9 @@ base::FilePath idb_directory = GetLevelDBPath(origin); EnsureDiskUsageCacheInitialized(origin); - leveldb::Status s = LevelDBDatabase::Destroy(idb_directory); + + leveldb::Status s = + indexed_db::DefaultLevelDBFactory().DestroyLevelDB(idb_directory); if (!s.ok()) { LOG(WARNING) << "Failed to delete LevelDB database: " << idb_directory.AsUTF8Unsafe(); @@ -372,14 +373,13 @@ ForceCloseReason reason) { DCHECK(TaskRunner()->RunsTasksInCurrentSequence()); UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.Context.ForceCloseReason", - reason, - FORCE_CLOSE_REASON_MAX); + reason, FORCE_CLOSE_REASON_MAX); if (!HasOrigin(origin)) return; - if (factory_.get()) - factory_->ForceClose(origin, reason == FORCE_CLOSE_DELETE_ORIGIN); + if (indexeddb_factory_.get()) + indexeddb_factory_->ForceClose(origin, reason == FORCE_CLOSE_DELETE_ORIGIN); DCHECK_EQ(0UL, GetConnectionCount(origin)); } @@ -389,8 +389,8 @@ if (is_incognito() || !HasOrigin(origin)) return false; - if (factory_.get()) { - factory_->ForceSchemaDowngrade(origin); + if (indexeddb_factory_.get()) { + indexeddb_factory_->ForceSchemaDowngrade(origin); return true; } this->ForceClose(origin, FORCE_SCHEMA_DOWNGRADE_INTERNALS_PAGE); @@ -404,8 +404,8 @@ if (is_incognito() || !HasOrigin(origin)) return V2SchemaCorruptionStatus::kUnknown; - if (factory_.get()) - return factory_->HasV2SchemaCorruption(origin); + if (indexeddb_factory_.get()) + return indexeddb_factory_->HasV2SchemaCorruption(origin); return V2SchemaCorruptionStatus::kUnknown; } @@ -414,10 +414,10 @@ if (!HasOrigin(origin)) return 0; - if (!factory_.get()) + if (!indexeddb_factory_.get()) return 0; - return factory_->GetConnectionCount(origin); + return indexeddb_factory_->GetConnectionCount(origin); } std::vector<base::FilePath> IndexedDBContextImpl::GetStoragePaths( @@ -463,12 +463,14 @@ quota_manager_proxy()->NotifyStorageAccessed( storage::QuotaClient::kIndexedDatabase, origin, blink::mojom::StorageType::kTemporary); - if (factory_.get() && factory_->GetConnectionCount(origin) == 0) + if (indexeddb_factory_.get() && + indexeddb_factory_->GetConnectionCount(origin) == 0) QueryDiskAndUpdateQuotaUsage(origin); } void IndexedDBContextImpl::TransactionComplete(const Origin& origin) { - DCHECK(!factory_.get() || factory_->GetConnectionCount(origin) > 0); + DCHECK(!indexeddb_factory_.get() || + indexeddb_factory_->GetConnectionCount(origin) > 0); QueryDiskAndUpdateQuotaUsage(origin); } @@ -508,10 +510,10 @@ } IndexedDBContextImpl::~IndexedDBContextImpl() { - if (factory_.get()) { + if (indexeddb_factory_.get()) { TaskRunner()->PostTask(FROM_HERE, base::BindOnce(&IndexedDBFactory::ContextDestroyed, - std::move(factory_))); + std::move(indexeddb_factory_))); } } @@ -549,46 +551,27 @@ base::DeleteFile(*file_path, true); } }, - data_path_, factory_, special_storage_policy_)); + data_path_, indexeddb_factory_, special_storage_policy_)); } } -// static -base::FilePath IndexedDBContextImpl::GetBlobStoreFileName( - const Origin& origin) { - std::string origin_id = storage::GetIdentifierFromOrigin(origin); - return base::FilePath() - .AppendASCII(origin_id) - .AddExtension(kIndexedDBExtension) - .AddExtension(kBlobExtension); -} - -// static -base::FilePath IndexedDBContextImpl::GetLevelDBFileName(const Origin& origin) { - std::string origin_id = storage::GetIdentifierFromOrigin(origin); - return base::FilePath() - .AppendASCII(origin_id) - .AddExtension(kIndexedDBExtension) - .AddExtension(kLevelDBExtension); -} - base::FilePath IndexedDBContextImpl::GetBlobStorePath( const Origin& origin) const { DCHECK(!is_incognito()); - return data_path_.Append(GetBlobStoreFileName(origin)); + return data_path_.Append(indexed_db::GetBlobStoreFileName(origin)); } base::FilePath IndexedDBContextImpl::GetLevelDBPath( const Origin& origin) const { DCHECK(!is_incognito()); - return data_path_.Append(GetLevelDBFileName(origin)); + return data_path_.Append(indexed_db::GetLevelDBFileName(origin)); } int64_t IndexedDBContextImpl::ReadUsageFromDisk(const Origin& origin) const { if (is_incognito()) { - if (!factory_) + if (!indexeddb_factory_) return 0; - return factory_->GetInMemoryDBSize(origin); + return indexeddb_factory_->GetInMemoryDBSize(origin); } int64_t total_size = 0;
diff --git a/content/browser/indexed_db/indexed_db_context_impl.h b/content/browser/indexed_db/indexed_db_context_impl.h index ea5fa2b..c599504d 100644 --- a/content/browser/indexed_db/indexed_db_context_impl.h +++ b/content/browser/indexed_db/indexed_db_context_impl.h
@@ -19,6 +19,7 @@ #include "base/macros.h" #include "content/browser/browser_main_loop.h" #include "content/browser/indexed_db/indexed_db_factory.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/public/browser/indexed_db_context.h" #include "storage/browser/quota/quota_manager_proxy.h" #include "storage/browser/quota/special_storage_policy.h" @@ -71,7 +72,8 @@ IndexedDBContextImpl( const base::FilePath& data_path, scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy, - scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy); + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy, + indexed_db::LevelDBFactory* leveldb_factory); IndexedDBFactory* GetIDBFactory(); @@ -99,9 +101,6 @@ void TransactionComplete(const url::Origin& origin); void DatabaseDeleted(const url::Origin& origin); - static base::FilePath GetBlobStoreFileName(const url::Origin& origin); - static base::FilePath GetLevelDBFileName(const url::Origin& origin); - // Called when blob files have been cleaned (an aggregated delayed task). void BlobFilesCleaned(const url::Origin& origin); @@ -178,7 +177,7 @@ // backing stores); the cache will be primed as needed by checking disk. std::set<url::Origin>* GetOriginSet(); - scoped_refptr<IndexedDBFactory> factory_; + scoped_refptr<IndexedDBFactory> indexeddb_factory_; // If |data_path_| is empty then this is an incognito session and the backing // store will be held in-memory rather than on-disk. @@ -192,6 +191,7 @@ std::unique_ptr<std::set<url::Origin>> origin_set_; std::map<url::Origin, int64_t> origin_size_map_; base::ObserverList<Observer>::Unchecked observers_; + indexed_db::LevelDBFactory* leveldb_factory_; DISALLOW_COPY_AND_ASSIGN(IndexedDBContextImpl); };
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host.cc b/content/browser/indexed_db/indexed_db_dispatcher_host.cc index 2685bf0..76e73c53 100644 --- a/content/browser/indexed_db/indexed_db_dispatcher_host.cc +++ b/content/browser/indexed_db/indexed_db_dispatcher_host.cc
@@ -144,6 +144,11 @@ void IndexedDBDispatcherHost::AddBinding( blink::mojom::IDBFactoryRequest request, const url::Origin& origin) { + if (!IsValidOrigin(origin)) { + mojo::ReportBadMessage(kInvalidOrigin); + return; + } + bindings_.AddBinding(this, std::move(request), {origin}); } @@ -174,11 +179,6 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); const auto& context = bindings_.dispatch_context(); - if (!IsValidOrigin(context.origin)) { - mojo::ReportBadMessage(kInvalidOrigin); - return; - } - scoped_refptr<IndexedDBCallbacks> callbacks( new IndexedDBCallbacks(this->AsWeakPtr(), context.origin, std::move(callbacks_info), IDBTaskRunner())); @@ -193,11 +193,6 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); const auto& context = bindings_.dispatch_context(); - if (!IsValidOrigin(context.origin)) { - mojo::ReportBadMessage(kInvalidOrigin); - return; - } - scoped_refptr<IndexedDBCallbacks> callbacks( new IndexedDBCallbacks(this->AsWeakPtr(), context.origin, std::move(callbacks_info), IDBTaskRunner())); @@ -216,11 +211,6 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); const auto& context = bindings_.dispatch_context(); - if (!IsValidOrigin(context.origin)) { - mojo::ReportBadMessage(kInvalidOrigin); - return; - } - scoped_refptr<IndexedDBCallbacks> callbacks( new IndexedDBCallbacks(this->AsWeakPtr(), context.origin, std::move(callbacks_info), IDBTaskRunner())); @@ -242,11 +232,6 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); const auto& context = bindings_.dispatch_context(); - if (!IsValidOrigin(context.origin)) { - mojo::ReportBadMessage(kInvalidOrigin); - return; - } - scoped_refptr<IndexedDBCallbacks> callbacks( new IndexedDBCallbacks(this->AsWeakPtr(), context.origin, std::move(callbacks_info), IDBTaskRunner())); @@ -262,11 +247,6 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); const auto& context = bindings_.dispatch_context(); - if (!IsValidOrigin(context.origin)) { - mojo::ReportBadMessage(kInvalidOrigin); - return; - } - base::OnceCallback<void(leveldb::Status)> callback_on_io = base::BindOnce( &CallCompactionStatusCallbackOnIOThread, base::ThreadTaskRunnerHandle::Get(), std::move(mojo_callback)); @@ -283,11 +263,6 @@ DCHECK_CURRENTLY_ON(BrowserThread::IO); const auto& context = bindings_.dispatch_context(); - if (!IsValidOrigin(context.origin)) { - mojo::ReportBadMessage(kInvalidOrigin); - return; - } - base::OnceCallback<void(leveldb::Status)> callback_on_io = base::BindOnce( &CallAbortStatusCallbackOnIOThread, base::ThreadTaskRunnerHandle::Get(), std::move(mojo_callback));
diff --git a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc index 193e3a5..0bd4a5a 100644 --- a/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc +++ b/content/browser/indexed_db/indexed_db_dispatcher_host_unittest.cc
@@ -19,6 +19,7 @@ #include "content/browser/indexed_db/indexed_db_database_callbacks.h" #include "content/browser/indexed_db/indexed_db_factory.h" #include "content/browser/indexed_db/indexed_db_pending_connection.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/browser/indexed_db/mock_mojo_indexed_db_callbacks.h" #include "content/browser/indexed_db/mock_mojo_indexed_db_database_callbacks.h" #include "content/public/browser/browser_task_traits.h" @@ -170,7 +171,8 @@ context_impl_(base::MakeRefCounted<IndexedDBContextImpl>( CreateAndReturnTempDir(&temp_dir_), special_storage_policy_, - quota_manager_->proxy())), + quota_manager_->proxy(), + indexed_db::GetDefaultLevelDBFactory())), host_(new IndexedDBDispatcherHost( kFakeProcessId, context_impl_,
diff --git a/content/browser/indexed_db/indexed_db_factory.h b/content/browser/indexed_db/indexed_db_factory.h index 4ade927..7a90e80 100644 --- a/content/browser/indexed_db/indexed_db_factory.h +++ b/content/browser/indexed_db/indexed_db_factory.h
@@ -10,6 +10,7 @@ #include <map> #include <memory> #include <set> +#include <tuple> #include <utility> #include "base/files/file_path.h" @@ -113,20 +114,12 @@ IndexedDBFactory() {} virtual ~IndexedDBFactory() {} - virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStore( - const url::Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - leveldb::Status* status) = 0; - - virtual scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( - const url::Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - bool first_time, - leveldb::Status* status) = 0; + virtual std::tuple<scoped_refptr<IndexedDBBackingStore>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* disk_full */> + OpenBackingStore(const url::Origin& origin, + const base::FilePath& data_directory) = 0; private: DISALLOW_COPY_AND_ASSIGN(IndexedDBFactory);
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.cc b/content/browser/indexed_db/indexed_db_factory_impl.cc index 392ca7d8..8d8baba 100644 --- a/content/browser/indexed_db/indexed_db_factory_impl.cc +++ b/content/browser/indexed_db/indexed_db_factory_impl.cc
@@ -119,9 +119,12 @@ constexpr const base::TimeDelta IndexedDBFactoryImpl::kMaxEarliestOriginSweepFromNow; -IndexedDBFactoryImpl::IndexedDBFactoryImpl(IndexedDBContextImpl* context, - base::Clock* clock) +IndexedDBFactoryImpl::IndexedDBFactoryImpl( + IndexedDBContextImpl* context, + indexed_db::LevelDBFactory* leveldb_factory, + base::Clock* clock) : context_(context), + leveldb_factory_(leveldb_factory), clock_(clock), earliest_sweep_(GenerateNextGlobalSweepTime(clock_->Now())) {} @@ -408,9 +411,9 @@ IndexedDBDataLossInfo data_loss_info; bool disk_full; leveldb::Status s; - // TODO(dmurph): Handle this error - scoped_refptr<IndexedDBBackingStore> backing_store = - OpenBackingStore(origin, data_directory, &data_loss_info, &disk_full, &s); + scoped_refptr<IndexedDBBackingStore> backing_store; + std::tie(backing_store, s, data_loss_info, disk_full) = + OpenBackingStore(origin, data_directory); if (!backing_store.get()) { IndexedDBDatabaseError error( blink::kWebIDBDatabaseExceptionUnknownError, @@ -448,13 +451,13 @@ const Origin& origin, const base::FilePath& data_directory) { IDB_TRACE("IndexedDBFactoryImpl::GetDatabaseNames"); - // TODO(dgrogan): Plumb data_loss back to script eventually? + // TODO(dmurph): Plumb data_loss back to script eventually? IndexedDBDataLossInfo data_loss_info; bool disk_full; leveldb::Status s; - // TODO(cmumford): Handle this error - scoped_refptr<IndexedDBBackingStore> backing_store = - OpenBackingStore(origin, data_directory, &data_loss_info, &disk_full, &s); + scoped_refptr<IndexedDBBackingStore> backing_store; + std::tie(backing_store, s, data_loss_info, disk_full) = + OpenBackingStore(origin, data_directory); if (!backing_store.get()) { IndexedDBDatabaseError error( blink::kWebIDBDatabaseExceptionUnknownError, @@ -502,12 +505,13 @@ return; } - // TODO(dgrogan): Plumb data_loss back to script eventually? + // TODO(dmurph): Plumb data_loss back to script eventually? IndexedDBDataLossInfo data_loss_info; - bool disk_full = false; + bool disk_full; leveldb::Status s; - scoped_refptr<IndexedDBBackingStore> backing_store = - OpenBackingStore(origin, data_directory, &data_loss_info, &disk_full, &s); + scoped_refptr<IndexedDBBackingStore> backing_store; + std::tie(backing_store, s, data_loss_info, disk_full) = + OpenBackingStore(origin, data_directory); if (!backing_store.get()) { IndexedDBDatabaseError error( blink::kWebIDBDatabaseExceptionUnknownError, @@ -641,8 +645,9 @@ HandleBackingStoreFailure(saved_origin); // Note: DestroyBackingStore only deletes LevelDB files, leaving all others, // so our corruption info file will remain. - leveldb::Status s = - IndexedDBBackingStore::DestroyBackingStore(path_base, saved_origin); + const base::FilePath file_path = + path_base.Append(indexed_db::GetLevelDBFileName(saved_origin)); + leveldb::Status s = leveldb_factory_->DestroyLevelDB(file_path); DLOG_IF(ERROR, !s.ok()) << "Unable to delete backing store: " << s.ToString(); UMA_HISTOGRAM_ENUMERATION( "WebCore.IndexedDB.DestroyCorruptBackingStoreStatus", @@ -669,69 +674,78 @@ it->second->pre_close_task_queue(); } -scoped_refptr<IndexedDBBackingStore> -IndexedDBFactoryImpl::OpenBackingStoreHelper( - const Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - bool first_time, - leveldb::Status* status) { - return IndexedDBBackingStore::Open( - this, origin, data_directory, data_loss_info, disk_full, - context_->TaskRunner(), first_time, status); -} - -scoped_refptr<IndexedDBBackingStore> IndexedDBFactoryImpl::OpenBackingStore( - const Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - leveldb::Status* status) { - const bool open_in_memory = data_directory.empty(); - +std::tuple<scoped_refptr<IndexedDBBackingStore>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* disk_full */> +IndexedDBFactoryImpl::OpenBackingStore(const Origin& origin, + const base::FilePath& data_directory) { const auto& it2 = backing_store_map_.find(origin); + scoped_refptr<IndexedDBBackingStore> backing_store; if (it2 != backing_store_map_.end()) { // Grab a refptr so the completion of the preclose task list doesn't close // the backing store. - scoped_refptr<IndexedDBBackingStore> backing_store = it2->second; + backing_store = it2->second; backing_store->close_timer()->Stop(); if (it2->second->pre_close_task_queue()) { backing_store->pre_close_task_queue()->StopForNewConnection(); backing_store->SetPreCloseTaskList(nullptr); } - return it2->second; + return {std::move(backing_store), leveldb::Status::OK(), + IndexedDBDataLossInfo(), false}; } - scoped_refptr<IndexedDBBackingStore> backing_store; - bool first_time = false; - if (open_in_memory) { - backing_store = IndexedDBBackingStore::OpenInMemory( - origin, context_->TaskRunner(), status); - } else { - first_time = !backends_opened_since_boot_.count(origin); - - backing_store = OpenBackingStoreHelper( - origin, data_directory, data_loss_info, disk_full, first_time, status); + base::FilePath blob_path; + base::FilePath database_path; + leveldb::Status s; + if (!data_directory.empty()) { + // The database will be on-disk and not in-memory. + std::tie(database_path, blob_path, s) = + indexed_db::CreateDatabaseDirectories(data_directory, origin); + if (!s.ok()) + return {std::move(backing_store), s, IndexedDBDataLossInfo(), false}; } + std::unique_ptr<LevelDBDatabase> database; + IndexedDBDataLossInfo data_loss_info; + bool disk_full; + std::tie(database, s, data_loss_info, disk_full) = + indexed_db::OpenAndVerifyLevelDBDatabase(origin, data_directory, + database_path, leveldb_factory_, + context_->TaskRunner()); + if (!s.ok()) + return {std::move(backing_store), s, data_loss_info, disk_full}; - if (backing_store.get()) { - if (first_time) - backends_opened_since_boot_.insert(origin); - backing_store_map_[origin] = backing_store; + backing_store = CreateBackingStore(origin, blob_path, std::move(database), + context_->TaskRunner()); - // If an in-memory database, bind lifetime to this factory instance. - if (open_in_memory) - in_memory_backing_stores_.insert(backing_store); - - // All backing stores associated with this factory should be of the same - // type. - DCHECK_NE(in_memory_backing_stores_.empty(), open_in_memory); - - return backing_store; + bool first_open_since_startup = + backends_opened_since_startup_.insert(origin).second; + s = backing_store->Initialize( + /*cleanup_live_journal=*/!database_path.empty() && + first_open_since_startup); + if (!s.ok()) { + backing_store.reset(); + return {std::move(backing_store), s, data_loss_info, disk_full}; } + // If an in-memory database, bind lifetime to this factory instance. + if (database_path.empty()) + in_memory_backing_stores_.insert(backing_store); + backing_store_map_[origin] = backing_store; - return nullptr; + // All backing stores associated with this factory should be of the same + // type. + DCHECK_EQ(!in_memory_backing_stores_.empty(), database_path.empty()); + DCHECK(backing_store); + return {std::move(backing_store), s, data_loss_info, disk_full}; +} + +scoped_refptr<IndexedDBBackingStore> IndexedDBFactoryImpl::CreateBackingStore( + const url::Origin& origin, + const base::FilePath& blob_path, + std::unique_ptr<LevelDBDatabase> db, + base::SequencedTaskRunner* task_runner) { + return base::MakeRefCounted<IndexedDBBackingStore>( + this, origin, blob_path, std::move(db), task_runner); } void IndexedDBFactoryImpl::Open( @@ -740,61 +754,56 @@ const Origin& origin, const base::FilePath& data_directory) { IDB_TRACE("IndexedDBFactoryImpl::Open"); - scoped_refptr<IndexedDBDatabase> database; IndexedDBDatabase::Identifier unique_identifier(origin, name); - const auto& it = database_map_.find(unique_identifier); - IndexedDBDataLossInfo data_loss_info; - bool disk_full = false; - bool was_open = (it != database_map_.end()); - if (!was_open) { - leveldb::Status s; - scoped_refptr<IndexedDBBackingStore> backing_store = OpenBackingStore( - origin, data_directory, &data_loss_info, &disk_full, &s); - if (!backing_store.get()) { - if (disk_full) { - connection->callbacks->OnError(IndexedDBDatabaseError( - blink::kWebIDBDatabaseExceptionQuotaError, - ASCIIToUTF16("Encountered full disk while opening " - "backing store for indexedDB.open."))); - return; - } - IndexedDBDatabaseError error( - blink::kWebIDBDatabaseExceptionUnknownError, - ASCIIToUTF16("Internal error opening backing store" - " for indexedDB.open.")); - connection->callbacks->OnError(error); - if (s.IsCorruption()) { - HandleBackingStoreCorruption(origin, error); - } + auto it = database_map_.find(unique_identifier); + if (it != database_map_.end()) { + it->second->OpenConnection(std::move(connection)); + return; + } + leveldb::Status s; + scoped_refptr<IndexedDBBackingStore> backing_store; + bool disk_full; + std::tie(backing_store, s, connection->data_loss_info, disk_full) = + OpenBackingStore(origin, data_directory); + if (!backing_store) { + if (disk_full) { + connection->callbacks->OnError(IndexedDBDatabaseError( + blink::kWebIDBDatabaseExceptionQuotaError, + ASCIIToUTF16("Encountered full disk while opening " + "backing store for indexedDB.open."))); return; } - - std::tie(database, s) = IndexedDBDatabase::Create( - name, backing_store.get(), this, - std::make_unique<IndexedDBMetadataCoding>(), unique_identifier); - if (!database.get()) { - DLOG(ERROR) << "Unable to create the database"; - IndexedDBDatabaseError error(blink::kWebIDBDatabaseExceptionUnknownError, - ASCIIToUTF16("Internal error creating " - "database backend for " - "indexedDB.open.")); - connection->callbacks->OnError(error); - if (s.IsCorruption()) { - backing_store = - nullptr; // Closes the LevelDB so that it can be deleted - HandleBackingStoreCorruption(origin, error); - } - return; + IndexedDBDatabaseError error( + blink::kWebIDBDatabaseExceptionUnknownError, + ASCIIToUTF16("Internal error opening backing store" + " for indexedDB.open.")); + connection->callbacks->OnError(error); + if (s.IsCorruption()) { + HandleBackingStoreCorruption(origin, error); } - } else { - database = it->second; + return; } - connection->data_loss_info = data_loss_info; + scoped_refptr<IndexedDBDatabase> database; + std::tie(database, s) = IndexedDBDatabase::Create( + name, backing_store.get(), this, + std::make_unique<IndexedDBMetadataCoding>(), unique_identifier); + if (!database.get()) { + DLOG(ERROR) << "Unable to create the database"; + IndexedDBDatabaseError error(blink::kWebIDBDatabaseExceptionUnknownError, + ASCIIToUTF16("Internal error creating " + "database backend for " + "indexedDB.open.")); + connection->callbacks->OnError(error); + if (s.IsCorruption()) { + backing_store = nullptr; // Closes the LevelDB so that it can be deleted + HandleBackingStoreCorruption(origin, error); + } + return; + } database->OpenConnection(std::move(connection)); - - if (!was_open && database->ConnectionCount() > 0) { + if (database->ConnectionCount() > 0) { database_map_[unique_identifier] = database.get(); origin_dbs_.insert(std::make_pair(origin, database.get())); }
diff --git a/content/browser/indexed_db/indexed_db_factory_impl.h b/content/browser/indexed_db/indexed_db_factory_impl.h index 5a95564..7ec91479 100644 --- a/content/browser/indexed_db/indexed_db_factory_impl.h +++ b/content/browser/indexed_db/indexed_db_factory_impl.h
@@ -10,12 +10,15 @@ #include <map> #include <memory> #include <set> +#include <tuple> +#include <utility> #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/time/clock.h" #include "base/time/time.h" #include "content/browser/indexed_db/indexed_db_factory.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" namespace base { struct Feature; @@ -47,7 +50,9 @@ static constexpr const base::TimeDelta kMaxEarliestOriginSweepFromNow = base::TimeDelta::FromDays(7); - IndexedDBFactoryImpl(IndexedDBContextImpl* context, base::Clock* clock); + IndexedDBFactoryImpl(IndexedDBContextImpl* context, + indexed_db::LevelDBFactory* leveldb_factory, + base::Clock* clock); // content::IndexedDBFactory overrides: void ReleaseDatabase(const IndexedDBDatabase::Identifier& identifier, @@ -118,20 +123,19 @@ protected: ~IndexedDBFactoryImpl() override; - scoped_refptr<IndexedDBBackingStore> OpenBackingStore( - const url::Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - leveldb::Status* s) override; + std::tuple<scoped_refptr<IndexedDBBackingStore>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* disk_full */> + OpenBackingStore(const url::Origin& origin, + const base::FilePath& data_directory) override; - scoped_refptr<IndexedDBBackingStore> OpenBackingStoreHelper( + // Used by unittests to allow subclassing of IndexedDBBackingStore. + virtual scoped_refptr<IndexedDBBackingStore> CreateBackingStore( const url::Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - bool first_time, - leveldb::Status* s) override; + const base::FilePath& blob_path, + std::unique_ptr<LevelDBDatabase> db, + base::SequencedTaskRunner* task_runner); void ReleaseBackingStore(const url::Origin& origin, bool immediate); void CloseBackingStore(const url::Origin& origin); @@ -174,6 +178,7 @@ void RemoveDatabaseFromMaps(const IndexedDBDatabase::Identifier& identifier); IndexedDBContextImpl* context_; + indexed_db::LevelDBFactory* leveldb_factory_; std::map<IndexedDBDatabase::Identifier, IndexedDBDatabase*> database_map_; OriginDBMap origin_dbs_; @@ -186,7 +191,7 @@ std::set<scoped_refptr<IndexedDBBackingStore>> in_memory_backing_stores_; std::map<url::Origin, scoped_refptr<IndexedDBBackingStore>> backing_stores_with_active_blobs_; - std::set<url::Origin> backends_opened_since_boot_; + std::set<url::Origin> backends_opened_since_startup_; base::Clock* clock_; base::Time earliest_sweep_;
diff --git a/content/browser/indexed_db/indexed_db_factory_unittest.cc b/content/browser/indexed_db/indexed_db_factory_unittest.cc index c4d1569..e7ce069 100644 --- a/content/browser/indexed_db/indexed_db_factory_unittest.cc +++ b/content/browser/indexed_db/indexed_db_factory_unittest.cc
@@ -22,6 +22,7 @@ #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/indexed_db/indexed_db_data_format_version.h" #include "content/browser/indexed_db/indexed_db_factory_impl.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/browser/indexed_db/mock_indexed_db_callbacks.h" #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -46,15 +47,18 @@ explicit MockIDBFactory(IndexedDBContextImpl* context) : MockIDBFactory(context, base::DefaultClock::GetInstance()) {} MockIDBFactory(IndexedDBContextImpl* context, base::Clock* clock) - : IndexedDBFactoryImpl(context, clock) {} + : IndexedDBFactoryImpl(context, + indexed_db::GetDefaultLevelDBFactory(), + clock) {} scoped_refptr<IndexedDBBackingStore> TestOpenBackingStore( const Origin& origin, const base::FilePath& data_directory) { IndexedDBDataLossInfo data_loss_info; bool disk_full; leveldb::Status s; - auto backing_store = OpenBackingStore(origin, data_directory, - &data_loss_info, &disk_full, &s); + scoped_refptr<IndexedDBBackingStore> backing_store; + std::tie(backing_store, s, data_loss_info, disk_full) = + OpenBackingStore(origin, data_directory); EXPECT_EQ(blink::mojom::IDBDataLoss::None, data_loss_info.status); return backing_store; } @@ -86,7 +90,7 @@ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); context_ = base::MakeRefCounted<IndexedDBContextImpl>( temp_dir_.GetPath(), /*special_storage_policy=*/nullptr, - quota_manager_proxy_.get()); + quota_manager_proxy_.get(), indexed_db::GetDefaultLevelDBFactory()); } void TearDown() override { @@ -415,19 +419,21 @@ class DiskFullFactory : public IndexedDBFactoryImpl { public: explicit DiskFullFactory(IndexedDBContextImpl* context) - : IndexedDBFactoryImpl(context, base::DefaultClock::GetInstance()) {} + : IndexedDBFactoryImpl(context, + indexed_db::GetDefaultLevelDBFactory(), + base::DefaultClock::GetInstance()) {} private: ~DiskFullFactory() override {} - scoped_refptr<IndexedDBBackingStore> OpenBackingStore( - const Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - leveldb::Status* s) override { - *disk_full = true; - *s = leveldb::Status::IOError("Disk is full"); - return scoped_refptr<IndexedDBBackingStore>(); + + std::tuple<scoped_refptr<IndexedDBBackingStore>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* disk_full */> + OpenBackingStore(const url::Origin& origin, + const base::FilePath& data_directory) override { + return std::make_tuple(nullptr, leveldb::Status::IOError("Disk is full"), + IndexedDBDataLossInfo(), true); } DISALLOW_COPY_AND_ASSIGN(DiskFullFactory);
diff --git a/content/browser/indexed_db/indexed_db_fake_backing_store.cc b/content/browser/indexed_db/indexed_db_fake_backing_store.cc index e83e2a7..9a7b452 100644 --- a/content/browser/indexed_db/indexed_db_fake_backing_store.cc +++ b/content/browser/indexed_db/indexed_db_fake_backing_store.cc
@@ -20,7 +20,6 @@ url::Origin::Create(GURL("http://localhost:81")), base::FilePath(), std::unique_ptr<LevelDBDatabase>(), - std::unique_ptr<LevelDBComparator>(), base::SequencedTaskRunnerHandle::Get().get()) {} IndexedDBFakeBackingStore::IndexedDBFakeBackingStore( IndexedDBFactory* factory, @@ -29,7 +28,6 @@ url::Origin::Create(GURL("http://localhost:81")), base::FilePath(), std::unique_ptr<LevelDBDatabase>(), - std::unique_ptr<LevelDBComparator>(), task_runner) {} IndexedDBFakeBackingStore::~IndexedDBFakeBackingStore() {}
diff --git a/content/browser/indexed_db/indexed_db_leveldb_coding.cc b/content/browser/indexed_db/indexed_db_leveldb_coding.cc index 80d5d12..bf1b0c9 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_coding.cc +++ b/content/browser/indexed_db/indexed_db_leveldb_coding.cc
@@ -21,59 +21,62 @@ using blink::IndexedDBKeyPath; namespace content { +namespace { // As most of the IndexedDBKeys and encoded values are short, we // initialize some std::vectors with a default inline buffer size to reduce // the memory re-allocations when the std::vectors are appended. -static const size_t kDefaultInlineBufferSize = 32; +const size_t kDefaultInlineBufferSize = 32; -static const unsigned char kIndexedDBKeyNullTypeByte = 0; -static const unsigned char kIndexedDBKeyStringTypeByte = 1; -static const unsigned char kIndexedDBKeyDateTypeByte = 2; -static const unsigned char kIndexedDBKeyNumberTypeByte = 3; -static const unsigned char kIndexedDBKeyArrayTypeByte = 4; -static const unsigned char kIndexedDBKeyMinKeyTypeByte = 5; -static const unsigned char kIndexedDBKeyBinaryTypeByte = 6; +constexpr unsigned char kIndexedDBKeyNullTypeByte = 0; +constexpr unsigned char kIndexedDBKeyStringTypeByte = 1; +constexpr unsigned char kIndexedDBKeyDateTypeByte = 2; +constexpr unsigned char kIndexedDBKeyNumberTypeByte = 3; +constexpr unsigned char kIndexedDBKeyArrayTypeByte = 4; +constexpr unsigned char kIndexedDBKeyMinKeyTypeByte = 5; +constexpr unsigned char kIndexedDBKeyBinaryTypeByte = 6; -static const unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0; -static const unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0; +constexpr unsigned char kIndexedDBKeyPathTypeCodedByte1 = 0; +constexpr unsigned char kIndexedDBKeyPathTypeCodedByte2 = 0; -static const unsigned char kIndexedDBKeyPathNullTypeByte = 0; -static const unsigned char kIndexedDBKeyPathStringTypeByte = 1; -static const unsigned char kIndexedDBKeyPathArrayTypeByte = 2; +constexpr unsigned char kIndexedDBKeyPathNullTypeByte = 0; +constexpr unsigned char kIndexedDBKeyPathStringTypeByte = 1; +constexpr unsigned char kIndexedDBKeyPathArrayTypeByte = 2; -static const unsigned char kObjectStoreDataIndexId = 1; -static const unsigned char kExistsEntryIndexId = 2; -static const unsigned char kBlobEntryIndexId = 3; +constexpr unsigned char kObjectStoreDataIndexId = 1; +constexpr unsigned char kExistsEntryIndexId = 2; +constexpr unsigned char kBlobEntryIndexId = 3; -static const unsigned char kSchemaVersionTypeByte = 0; -static const unsigned char kMaxDatabaseIdTypeByte = 1; -static const unsigned char kDataVersionTypeByte = 2; -static const unsigned char kBlobJournalTypeByte = 3; -static const unsigned char kLiveBlobJournalTypeByte = 4; -static const unsigned char kEarliestSweepTimeTypeByte = 5; -static const unsigned char kMaxSimpleGlobalMetaDataTypeByte = +constexpr unsigned char kSchemaVersionTypeByte = 0; +constexpr unsigned char kMaxDatabaseIdTypeByte = 1; +constexpr unsigned char kDataVersionTypeByte = 2; +constexpr unsigned char kBlobJournalTypeByte = 3; +constexpr unsigned char kLiveBlobJournalTypeByte = 4; +constexpr unsigned char kEarliestSweepTimeTypeByte = 5; +constexpr unsigned char kMaxSimpleGlobalMetaDataTypeByte = 6; // Insert before this and increment. -static const unsigned char kDatabaseFreeListTypeByte = 100; -static const unsigned char kDatabaseNameTypeByte = 201; +constexpr unsigned char kDatabaseFreeListTypeByte = 100; +constexpr unsigned char kDatabaseNameTypeByte = 201; -static const unsigned char kObjectStoreMetaDataTypeByte = 50; -static const unsigned char kIndexMetaDataTypeByte = 100; -static const unsigned char kObjectStoreFreeListTypeByte = 150; -static const unsigned char kIndexFreeListTypeByte = 151; -static const unsigned char kObjectStoreNamesTypeByte = 200; -static const unsigned char kIndexNamesKeyTypeByte = 201; +constexpr unsigned char kObjectStoreMetaDataTypeByte = 50; +constexpr unsigned char kIndexMetaDataTypeByte = 100; +constexpr unsigned char kObjectStoreFreeListTypeByte = 150; +constexpr unsigned char kIndexFreeListTypeByte = 151; +constexpr unsigned char kObjectStoreNamesTypeByte = 200; +constexpr unsigned char kIndexNamesKeyTypeByte = 201; -static const unsigned char kObjectMetaDataTypeMaximum = 255; -static const unsigned char kIndexMetaDataTypeMaximum = 255; - -const unsigned char kMinimumIndexId = 30; +constexpr unsigned char kObjectMetaDataTypeMaximum = 255; +constexpr unsigned char kIndexMetaDataTypeMaximum = 255; inline void EncodeIntSafely(int64_t value, int64_t max, std::string* into) { DCHECK_LE(value, max); return EncodeInt(value, into); } +} // namespace + +const unsigned char kMinimumIndexId = 30; + std::string MaxIDBKey() { std::string ret; EncodeByte(kIndexedDBKeyNullTypeByte, &ret); @@ -986,6 +989,7 @@ bool only_compare_index_keys) { bool ok; int result = Compare(a, b, only_compare_index_keys, &ok); + // TODO(dmurph): Report this somehow. https://crbug.com/913121 DCHECK(ok); if (!ok) return 0;
diff --git a/content/browser/indexed_db/indexed_db_leveldb_operations.cc b/content/browser/indexed_db/indexed_db_leveldb_operations.cc index 1e981b9..9469413 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_operations.cc +++ b/content/browser/indexed_db/indexed_db_leveldb_operations.cc
@@ -4,11 +4,22 @@ #include "content/browser/indexed_db/indexed_db_leveldb_operations.h" +#include "base/files/file_util.h" +#include "base/json/json_reader.h" +#include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" +#include "base/values.h" +#include "content/browser/indexed_db/indexed_db_data_format_version.h" +#include "content/browser/indexed_db/indexed_db_data_loss_info.h" #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" #include "content/browser/indexed_db/indexed_db_reporting.h" +#include "content/browser/indexed_db/indexed_db_tracing.h" #include "content/browser/indexed_db/leveldb/leveldb_database.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/browser/indexed_db/leveldb/leveldb_iterator.h" #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" +#include "storage/common/database/database_identifier.h" +#include "third_party/leveldatabase/env_chromium.h" using base::StringPiece; using blink::IndexedDBKeyPath; @@ -16,20 +27,61 @@ namespace content { namespace indexed_db { - -leveldb::Status InternalInconsistencyStatus() { - return leveldb::Status::Corruption("Internal inconsistency"); -} - -leveldb::Status InvalidDBKeyStatus() { - return leveldb::Status::InvalidArgument("Invalid database key ID"); -} - -leveldb::Status IOErrorStatus() { - return leveldb::Status::IOError("IO Error"); -} - namespace { + +class IDBComparator : public LevelDBComparator { + public: + IDBComparator() = default; + ~IDBComparator() override = default; + int Compare(const base::StringPiece& a, + const base::StringPiece& b) const override { + return content::Compare(a, b, false /*index_keys*/); + } + const char* Name() const override { return "idb_cmp1"; } +}; + +class LDBComparator : public leveldb::Comparator { + public: + LDBComparator() = default; + ~LDBComparator() override = default; + int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const override { + return content::Compare(leveldb_env::MakeStringPiece(a), + leveldb_env::MakeStringPiece(b), + false /*index_keys*/); + } + const char* Name() const override { return "idb_cmp1"; } + void FindShortestSeparator(std::string* start, + const leveldb::Slice& limit) const override {} + void FindShortSuccessor(std::string* key) const override {} +}; + +bool IsPathTooLong(const base::FilePath& leveldb_dir) { + int limit = base::GetMaximumPathComponentLength(leveldb_dir.DirName()); + if (limit == -1) { + DLOG(WARNING) << "GetMaximumPathComponentLength returned -1"; +// In limited testing, ChromeOS returns 143, other OSes 255. +#if defined(OS_CHROMEOS) + limit = 143; +#else + limit = 255; +#endif + } + size_t component_length = leveldb_dir.BaseName().value().length(); + if (component_length > static_cast<uint32_t>(limit)) { + DLOG(WARNING) << "Path component length (" << component_length + << ") exceeds maximum (" << limit + << ") allowed by this filesystem."; + const int min = 140; + const int max = 300; + const int num_buckets = 12; + UMA_HISTOGRAM_CUSTOM_COUNTS( + "WebCore.IndexedDB.BackingStore.OverlyLargeOriginLength", + component_length, min, max, num_buckets); + return true; + } + return false; +} + template <typename DBOrTransaction> Status GetIntInternal(DBOrTransaction* db, const StringPiece& key, @@ -46,8 +98,161 @@ return s; return InternalInconsistencyStatus(); } + +WARN_UNUSED_RESULT bool IsSchemaKnown(LevelDBDatabase* db, bool* known) { + int64_t db_schema_version = 0; + bool found = false; + Status s = GetInt(db, SchemaVersionKey::Encode(), &db_schema_version, &found); + if (!s.ok()) + return false; + if (!found) { + *known = true; + return true; + } + if (db_schema_version < 0) + return false; // Only corruption should cause this. + if (db_schema_version > indexed_db::kLatestKnownSchemaVersion) { + *known = false; + return true; + } + + int64_t raw_db_data_version = 0; + s = GetInt(db, DataVersionKey::Encode(), &raw_db_data_version, &found); + if (!s.ok()) + return false; + if (!found) { + *known = true; + return true; + } + if (raw_db_data_version < 0) + return false; // Only corruption should cause this. + + *known = IndexedDBDataFormatVersion::GetCurrent().IsAtLeast( + IndexedDBDataFormatVersion::Decode(raw_db_data_version)); + return true; +} +std::tuple<std::unique_ptr<LevelDBDatabase>, + leveldb::Status, + bool /* is_disk_full */> +DeleteAndRecreateDatabase( + const url::Origin& origin, + base::FilePath database_path, + LevelDBFactory* ldb_factory, + scoped_refptr<base::SequencedTaskRunner> task_runner) { + scoped_refptr<LevelDBState> state; + DCHECK(!database_path.empty()) + << "Opening an in-memory database should not have failed."; + LOG(ERROR) << "IndexedDB backing store open failed, attempting cleanup"; + state.reset(); + leveldb::Status status = ldb_factory->DestroyLevelDB(database_path); + if (!status.ok()) { + LOG(ERROR) << "IndexedDB backing store cleanup failed"; + ReportOpenStatus( + indexed_db::INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_DESTROY_FAILED, + origin); + return {nullptr, status, false}; + } + + LOG(ERROR) << "IndexedDB backing store cleanup succeeded, reopening"; + state.reset(); + bool is_disk_full; + std::tie(state, status, is_disk_full) = + ldb_factory->OpenLevelDB(database_path, GetDefaultIndexedDBComparator(), + GetDefaultLevelDBComparator()); + if (!status.ok()) { + LOG(ERROR) << "IndexedDB backing store reopen after recovery failed"; + ReportOpenStatus( + indexed_db::INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_FAILED, + origin); + return {nullptr, status, is_disk_full}; + } + std::unique_ptr<LevelDBDatabase> database = std::make_unique<LevelDBDatabase>( + std::move(state), std::move(task_runner), + LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase); + ReportOpenStatus( + indexed_db::INDEXED_DB_BACKING_STORE_OPEN_CLEANUP_REOPEN_SUCCESS, origin); + + return {std::move(database), status, is_disk_full}; +} + } // namespace +const base::FilePath::CharType kBlobExtension[] = FILE_PATH_LITERAL(".blob"); +const base::FilePath::CharType kIndexedDBExtension[] = + FILE_PATH_LITERAL(".indexeddb"); +const base::FilePath::CharType kLevelDBExtension[] = + FILE_PATH_LITERAL(".leveldb"); + +// static +base::FilePath GetBlobStoreFileName(const url::Origin& origin) { + std::string origin_id = storage::GetIdentifierFromOrigin(origin); + return base::FilePath() + .AppendASCII(origin_id) + .AddExtension(kIndexedDBExtension) + .AddExtension(kBlobExtension); +} + +// static +base::FilePath GetLevelDBFileName(const url::Origin& origin) { + std::string origin_id = storage::GetIdentifierFromOrigin(origin); + return base::FilePath() + .AppendASCII(origin_id) + .AddExtension(kIndexedDBExtension) + .AddExtension(kLevelDBExtension); +} + +base::FilePath ComputeCorruptionFileName(const url::Origin& origin) { + return GetLevelDBFileName(origin).Append( + FILE_PATH_LITERAL("corruption_info.json")); +} + +std::string ReadCorruptionInfo(const base::FilePath& path_base, + const url::Origin& origin) { + const base::FilePath info_path = + path_base.Append(ComputeCorruptionFileName(origin)); + std::string message; + if (IsPathTooLong(info_path)) + return message; + + const int64_t kMaxJsonLength = 4096; + int64_t file_size = 0; + if (!base::GetFileSize(info_path, &file_size)) + return message; + if (!file_size || file_size > kMaxJsonLength) { + base::DeleteFile(info_path, false); + return message; + } + + base::File file(info_path, base::File::FLAG_OPEN | base::File::FLAG_READ); + if (file.IsValid()) { + std::string input_js(file_size, '\0'); + if (file_size == file.Read(0, base::data(input_js), file_size)) { + base::JSONReader reader; + std::unique_ptr<base::DictionaryValue> val( + base::DictionaryValue::From(reader.ReadToValue(input_js))); + if (val) + val->GetString("message", &message); + } + file.Close(); + } + + base::DeleteFile(info_path, false); + + return message; +} + +leveldb::Status InternalInconsistencyStatus() { + return leveldb::Status::Corruption("Internal inconsistency"); +} + +leveldb::Status InvalidDBKeyStatus() { + return leveldb::Status::InvalidArgument("Invalid database key ID"); +} + +leveldb::Status IOErrorStatus() { + return leveldb::Status::IOError("IO Error"); +} + Status GetInt(LevelDBTransaction* txn, const StringPiece& key, int64_t* found_int, @@ -415,7 +620,7 @@ LevelDBTransaction* leveldb_transaction, int64_t database_id, int64_t blob_key_generator_current_number) { -#ifndef NDEBUG +#if DCHECK_IS_ON() int64_t old_number; if (!GetBlobKeyGeneratorCurrentNumber(leveldb_transaction, database_id, &old_number)) @@ -455,5 +660,142 @@ indexed_db::PutInt(txn, earliest_sweep_time_key, time_micros); } +const LevelDBComparator* GetDefaultIndexedDBComparator() { + static const base::NoDestructor<IDBComparator> kIDBComparator; + return kIDBComparator.get(); +} + +const leveldb::Comparator* GetDefaultLevelDBComparator() { + static const base::NoDestructor<LDBComparator> ldb_comparator; + return ldb_comparator.get(); +} + +std::tuple<base::FilePath /*leveldb_path*/, + base::FilePath /*blob_path*/, + leveldb::Status> +CreateDatabaseDirectories(const base::FilePath& path_base, + const url::Origin& origin) { + leveldb::Status status; + if (!base::CreateDirectoryAndGetError(path_base, nullptr)) { + status = Status::IOError("Unable to create IndexedDB database path"); + LOG(ERROR) << status.ToString() << ": \"" << path_base.AsUTF8Unsafe() + << "\""; + ReportOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_DIRECTORY, + origin); + return {base::FilePath(), base::FilePath(), status}; + } + + base::FilePath leveldb_path = path_base.Append(GetLevelDBFileName(origin)); + base::FilePath blob_path = path_base.Append(GetBlobStoreFileName(origin)); + if (IsPathTooLong(leveldb_path)) { + ReportOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_ORIGIN_TOO_LONG, + origin); + status = Status::IOError("File path too long"); + return {base::FilePath(), base::FilePath(), status}; + } + return {leveldb_path, blob_path, status}; +} + +std::tuple<std::unique_ptr<LevelDBDatabase>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* is_disk_full */> +OpenAndVerifyLevelDBDatabase( + const url::Origin& origin, + base::FilePath path_base, + base::FilePath database_path, + LevelDBFactory* ldb_factory, + scoped_refptr<base::SequencedTaskRunner> task_runner) { + // Please see docs/open_and_verify_leveldb_database.code2flow, and the + // generated pdf (from https://code2flow.com). + // The intended strategy here is to have this function match that flowchart, + // where the flowchart should be seen as the 'master' logic template. Please + // check the git history of both to make sure they are supposed to be in sync. + DCHECK_EQ(database_path.empty(), path_base.empty()); + IDB_TRACE("indexed_db::OpenAndVerifyLevelDBDatabase"); + bool is_disk_full; + std::unique_ptr<LevelDBDatabase> database; + leveldb::Status status; + scoped_refptr<LevelDBState> state; + std::tie(state, status, is_disk_full) = + ldb_factory->OpenLevelDB(database_path, GetDefaultIndexedDBComparator(), + GetDefaultLevelDBComparator()); + bool is_schema_known = false; + // On I/O error the database isn't deleted, in case the issue is temporary. + if (status.IsIOError()) { + ReportOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_NO_RECOVERY, + origin); + return {std::move(database), status, IndexedDBDataLossInfo(), is_disk_full}; + } + + IndexedDBDataLossInfo data_loss_info; + data_loss_info.status = blink::mojom::IDBDataLoss::None; + if (status.IsCorruption()) { + // On corruption, recovery will happen in the next section. + data_loss_info.status = blink::mojom::IDBDataLoss::Total; + data_loss_info.message = leveldb_env::GetCorruptionMessage(status); + std::tie(database, status, is_disk_full) = DeleteAndRecreateDatabase( + origin, database_path, ldb_factory, task_runner); + // If successful, then the database should be empty and doesn't need any of + // the corruption or schema checks below. + if (status.ok()) { + ReportOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, + origin); + } + return {std::move(database), status, data_loss_info, is_disk_full}; + } + // The leveldb database is successfully opened. + DCHECK(status.ok()); + database = std::make_unique<LevelDBDatabase>( + std::move(state), std::move(task_runner), + LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase); + + // Check for previous corruption or invalid schemas. + std::string corruption_message; + if (!path_base.empty()) + corruption_message = ReadCorruptionInfo(path_base, origin); + if (!corruption_message.empty()) { + LOG(ERROR) << "IndexedDB recovering from a corrupted (and deleted) " + "database."; + ReportOpenStatus( + indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_PRIOR_CORRUPTION, + origin); + status = leveldb::Status::Corruption(corruption_message); + database.reset(); + data_loss_info.status = blink::mojom::IDBDataLoss::Total; + data_loss_info.message = + "IndexedDB (database was corrupt): " + corruption_message; + } else if (!IsSchemaKnown(database.get(), &is_schema_known)) { + LOG(ERROR) << "IndexedDB had IO error checking schema, treating it as " + "failure to open"; + ReportOpenStatus( + indexed_db:: + INDEXED_DB_BACKING_STORE_OPEN_FAILED_IO_ERROR_CHECKING_SCHEMA, + origin); + database.reset(); + data_loss_info.status = blink::mojom::IDBDataLoss::Total; + data_loss_info.message = "I/O error checking schema"; + } else if (!is_schema_known) { + LOG(ERROR) << "IndexedDB backing store had unknown schema, treating it " + "as failure to open"; + ReportOpenStatus( + indexed_db::INDEXED_DB_BACKING_STORE_OPEN_FAILED_UNKNOWN_SCHEMA, + origin); + database.reset(); + data_loss_info.status = blink::mojom::IDBDataLoss::Total; + data_loss_info.message = "Unknown schema"; + } + // Try to delete & recreate the database for any of the above issues. + if (!database.get()) { + DCHECK(!is_schema_known || status.IsCorruption()); + std::tie(database, status, is_disk_full) = DeleteAndRecreateDatabase( + origin, database_path, ldb_factory, task_runner); + } + + if (status.ok()) + ReportOpenStatus(indexed_db::INDEXED_DB_BACKING_STORE_OPEN_SUCCESS, origin); + return {std::move(database), status, data_loss_info, is_disk_full}; +} + } // namespace indexed_db } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_leveldb_operations.h b/content/browser/indexed_db/indexed_db_leveldb_operations.h index fbbc9957..dfa747e 100644 --- a/content/browser/indexed_db/indexed_db_leveldb_operations.h +++ b/content/browser/indexed_db/indexed_db_leveldb_operations.h
@@ -5,14 +5,23 @@ #ifndef CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_LEVELDB_OPERATIONS_H_ #define CONTENT_BROWSER_INDEXED_DB_INDEXED_DB_LEVELDB_OPERATIONS_H_ +#include <memory> #include <string> +#include <tuple> +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequenced_task_runner.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" #include "base/time/time.h" +#include "content/browser/indexed_db/leveldb/leveldb_comparator.h" #include "content/common/content_export.h" #include "third_party/blink/public/common/indexeddb/indexeddb_key_path.h" +#include "third_party/leveldatabase/src/include/leveldb/comparator.h" #include "third_party/leveldatabase/src/include/leveldb/status.h" +#include "url/origin.h" // Contains common operations for LevelDBTransactions and/or LevelDBDatabases. @@ -20,8 +29,25 @@ class LevelDBDatabase; class LevelDBIterator; class LevelDBTransaction; +struct IndexedDBDataLossInfo; namespace indexed_db { +class LevelDBFactory; + +extern const base::FilePath::CharType kBlobExtension[]; +extern const base::FilePath::CharType kIndexedDBExtension[]; +extern const base::FilePath::CharType kLevelDBExtension[]; + +base::FilePath GetBlobStoreFileName(const url::Origin& origin); +base::FilePath GetLevelDBFileName(const url::Origin& origin); +base::FilePath ComputeCorruptionFileName(const url::Origin& origin); + +// If a corruption file for the given |origin| at the given |path_base| exists +// it is deleted, and the message is returned. If the file does not exist, or if +// there is an error parsing the message, then this method returns an empty +// string (and deletes the file). +std::string CONTENT_EXPORT ReadCorruptionInfo(const base::FilePath& path_base, + const url::Origin& origin); // Was able to use LevelDB to read the data w/o error, but the data read was not // in the expected format. @@ -139,6 +165,32 @@ void SetEarliestSweepTime(LevelDBTransaction* txn, base::Time earliest_sweep); +CONTENT_EXPORT const LevelDBComparator* GetDefaultIndexedDBComparator(); + +CONTENT_EXPORT const leveldb::Comparator* GetDefaultLevelDBComparator(); + +// Creates the leveldb and blob storage directories for IndexedDB. +std::tuple<base::FilePath /*leveldb_path*/, + base::FilePath /*blob_path*/, + leveldb::Status> +CreateDatabaseDirectories(const base::FilePath& path_base, + const url::Origin& origin); + +// |path_base| is the directory that will contain the database directory, the +// blob directory, and any data loss info. |database_path| is the directory for +// the leveldb database. If |path_base| is empty, then an in-memory database is +// opened. +std::tuple<std::unique_ptr<LevelDBDatabase>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* is_disk_full */> +OpenAndVerifyLevelDBDatabase( + const url::Origin& origin, + base::FilePath path_base, + base::FilePath database_path, + LevelDBFactory* ldb_factory, + scoped_refptr<base::SequencedTaskRunner> task_runner); + } // namespace indexed_db } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc index 529c597..be0d471c 100644 --- a/content/browser/indexed_db/indexed_db_quota_client_unittest.cc +++ b/content/browser/indexed_db/indexed_db_quota_client_unittest.cc
@@ -18,6 +18,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/indexed_db/indexed_db_quota_client.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/public/browser/storage_partition.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -56,7 +57,8 @@ idb_context_ = new IndexedDBContextImpl( browser_context_->GetPath(), - browser_context_->GetSpecialStoragePolicy(), quota_manager->proxy()); + browser_context_->GetSpecialStoragePolicy(), quota_manager->proxy(), + indexed_db::GetDefaultLevelDBFactory()); base::RunLoop().RunUntilIdle(); setup_temp_dir(); }
diff --git a/content/browser/indexed_db/indexed_db_reporting.cc b/content/browser/indexed_db/indexed_db_reporting.cc index 199141c..b8c4baa 100644 --- a/content/browser/indexed_db/indexed_db_reporting.cc +++ b/content/browser/indexed_db/indexed_db_reporting.cc
@@ -7,7 +7,9 @@ #include <string> #include "base/metrics/histogram_macros.h" +#include "base/strings/strcat.h" #include "content/browser/indexed_db/indexed_db_leveldb_coding.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "url/origin.h" namespace content { @@ -21,10 +23,46 @@ return std::string(); } +void ParseAndReportIOErrorDetails(const std::string& histogram_name, + const leveldb::Status& s) { + leveldb_env::MethodID method; + base::File::Error error = base::File::FILE_OK; + leveldb_env::ErrorParsingResult result = + leveldb_env::ParseMethodAndError(s, &method, &error); + if (result == leveldb_env::NONE) + return; + base::LinearHistogram::FactoryGet( + base::StrCat({histogram_name, ".EnvMethod"}), 1, leveldb_env::kNumEntries, + leveldb_env::kNumEntries + 1, + base::HistogramBase::kUmaTargetedHistogramFlag) + ->Add(method); + + if (result == leveldb_env::METHOD_AND_BFE) { + DCHECK_LT(error, 0); + base::LinearHistogram::FactoryGet( + base::StrCat( + {histogram_name, ".BFE.", leveldb_env::MethodIDToString(method)}), + 1, -base::File::FILE_ERROR_MAX, -base::File::FILE_ERROR_MAX + 1, + base::HistogramBase::kUmaTargetedHistogramFlag) + ->Add(-error); + } +} + +void ParseAndReportCorruptionDetails(const std::string& histogram_name, + const leveldb::Status& status) { + int error = leveldb_env::GetCorruptionCode(status); + DCHECK_GE(error, 0); + const int kNumPatterns = leveldb_env::GetNumCorruptionCodes(); + base::LinearHistogram::FactoryGet( + base::StrCat({histogram_name, ".Corruption"}), 1, kNumPatterns, + kNumPatterns + 1, base::HistogramBase::kUmaTargetedHistogramFlag) + ->Add(error); +} + } // namespace -void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, - const url::Origin& origin) { +void ReportOpenStatus(IndexedDBBackingStoreOpenResult result, + const url::Origin& origin) { UMA_HISTOGRAM_ENUMERATION("WebCore.IndexedDB.BackingStore.OpenStatus", result, INDEXED_DB_BACKING_STORE_OPEN_MAX); const std::string suffix = OriginToCustomHistogramSuffix(origin); @@ -34,7 +72,7 @@ // separately (below). if (!suffix.empty()) { base::LinearHistogram::FactoryGet( - "WebCore.IndexedDB.BackingStore.OpenStatus" + suffix, 1, + base::StrCat({"WebCore.IndexedDB.BackingStore.OpenStatus", suffix}), 1, INDEXED_DB_BACKING_STORE_OPEN_MAX, INDEXED_DB_BACKING_STORE_OPEN_MAX + 1, base::HistogramBase::kUmaTargetedHistogramFlag) @@ -44,11 +82,10 @@ void ReportInternalError(const char* type, IndexedDBBackingStoreErrorSource location) { - std::string name; - name.append("WebCore.IndexedDB.BackingStore.").append(type).append("Error"); - base::Histogram::FactoryGet(name, 1, INTERNAL_ERROR_MAX, - INTERNAL_ERROR_MAX + 1, - base::HistogramBase::kUmaTargetedHistogramFlag) + base::Histogram::FactoryGet( + base::StrCat({"WebCore.IndexedDB.BackingStore.", type, "Error"}), 1, + INTERNAL_ERROR_MAX, INTERNAL_ERROR_MAX + 1, + base::HistogramBase::kUmaTargetedHistogramFlag) ->Add(location); } @@ -58,7 +95,7 @@ const std::string suffix = OriginToCustomHistogramSuffix(origin); if (!suffix.empty()) { base::LinearHistogram::FactoryGet( - "WebCore.IndexedDB.SchemaVersion" + suffix, 0, + base::StrCat({"WebCore.IndexedDB.SchemaVersion", suffix}), 0, indexed_db::kLatestKnownSchemaVersion, indexed_db::kLatestKnownSchemaVersion + 1, base::HistogramBase::kUmaTargetedHistogramFlag) @@ -71,11 +108,41 @@ const std::string suffix = OriginToCustomHistogramSuffix(origin); if (!suffix.empty()) { base::BooleanHistogram::FactoryGet( - "WebCore.IndexedDB.SchemaV2HasBlobs" + suffix, + base::StrCat({"WebCore.IndexedDB.SchemaV2HasBlobs", suffix}), base::HistogramBase::kUmaTargetedHistogramFlag) ->Add(has_broken_blobs); } } +void ReportLevelDBError(const std::string& histogram_name, + const leveldb::Status& s) { + if (s.ok()) { + NOTREACHED(); + return; + } + enum { + LEVEL_DB_NOT_FOUND, + LEVEL_DB_CORRUPTION, + LEVEL_DB_IO_ERROR, + LEVEL_DB_OTHER, + LEVEL_DB_MAX_ERROR + }; + int leveldb_error = LEVEL_DB_OTHER; + if (s.IsNotFound()) + leveldb_error = LEVEL_DB_NOT_FOUND; + else if (s.IsCorruption()) + leveldb_error = LEVEL_DB_CORRUPTION; + else if (s.IsIOError()) + leveldb_error = LEVEL_DB_IO_ERROR; + base::Histogram::FactoryGet(histogram_name, 1, LEVEL_DB_MAX_ERROR, + LEVEL_DB_MAX_ERROR + 1, + base::HistogramBase::kUmaTargetedHistogramFlag) + ->Add(leveldb_error); + if (s.IsIOError()) + ParseAndReportIOErrorDetails(histogram_name, s); + else + ParseAndReportCorruptionDetails(histogram_name, s); +} + } // namespace indexed_db } // namespace content
diff --git a/content/browser/indexed_db/indexed_db_reporting.h b/content/browser/indexed_db/indexed_db_reporting.h index ef82e103..6fe9fde 100644 --- a/content/browser/indexed_db/indexed_db_reporting.h +++ b/content/browser/indexed_db/indexed_db_reporting.h
@@ -73,8 +73,8 @@ INDEXED_DB_BACKING_STORE_OPEN_MAX, }; -void HistogramOpenStatus(IndexedDBBackingStoreOpenResult result, - const url::Origin& origin); +void ReportOpenStatus(IndexedDBBackingStoreOpenResult result, + const url::Origin& origin); void ReportInternalError(const char* type, IndexedDBBackingStoreErrorSource location); @@ -83,6 +83,9 @@ void ReportV2Schema(bool has_broken_blobs, const url::Origin& origin); +void ReportLevelDBError(const std::string& histogram_name, + const leveldb::Status& s); + // Use to signal conditions caused by data corruption. // A macro is used instead of an inline function so that the assert and log // report the line number.
diff --git a/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc b/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc index 77ea5cc..f37faf3 100644 --- a/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc +++ b/content/browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc
@@ -5,14 +5,17 @@ #include "content/browser/indexed_db/indexed_db_tombstone_sweeper.h" #include <memory> +#include <utility> #include "base/files/scoped_temp_dir.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" #include "base/test/metrics/histogram_tester.h" #include "base/time/tick_clock.h" +#include "content/browser/indexed_db/indexed_db_leveldb_operations.h" #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" #include "content/browser/indexed_db/leveldb/leveldb_database.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/browser/indexed_db/leveldb/mock_level_db.h" #include "content/public/test/test_browser_thread_bundle.h" #include "testing/gmock/include/gmock/gmock.h" @@ -77,15 +80,6 @@ MOCK_CONST_METHOD0(NowTicks, base::TimeTicks()); }; -class Comparator : public LevelDBComparator { - public: - int Compare(const base::StringPiece& a, - const base::StringPiece& b) const override { - return content::Compare(a, b, false /*index_keys*/); - } - const char* Name() const override { return "idb_cmp1"; } -}; - class IndexedDBTombstoneSweeperTest : public testing::TestWithParam<Mode> { public: IndexedDBTombstoneSweeperTest() {} @@ -143,8 +137,16 @@ } void SetupRealDB() { - comparator_.reset(new Comparator()); - in_memory_db_ = LevelDBDatabase::OpenInMemory(comparator_.get()); + scoped_refptr<LevelDBState> level_db_state; + leveldb::Status s; + std::tie(level_db_state, s, std::ignore) = + indexed_db::GetDefaultLevelDBFactory()->OpenLevelDB( + base::FilePath(), indexed_db::GetDefaultIndexedDBComparator(), + indexed_db::GetDefaultLevelDBComparator()); + ASSERT_TRUE(s.ok()); + in_memory_db_ = std::make_unique<LevelDBDatabase>( + std::move(level_db_state), nullptr, + LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase); sweeper_ = std::make_unique<IndexedDBTombstoneSweeper>( GetParam(), kRoundIterations, kMaxIterations, in_memory_db_->db()); sweeper_->SetStartSeedsForTesting(0, 0, 0); @@ -239,7 +241,6 @@ } protected: - std::unique_ptr<Comparator> comparator_; std::unique_ptr<LevelDBDatabase> in_memory_db_; leveldb::MockLevelDB mock_db_;
diff --git a/content/browser/indexed_db/indexed_db_unittest.cc b/content/browser/indexed_db/indexed_db_unittest.cc index 10c541b..2b923a12 100644 --- a/content/browser/indexed_db/indexed_db_unittest.cc +++ b/content/browser/indexed_db/indexed_db_unittest.cc
@@ -14,6 +14,7 @@ #include "content/browser/indexed_db/indexed_db_connection.h" #include "content/browser/indexed_db/indexed_db_context_impl.h" #include "content/browser/indexed_db/indexed_db_factory_impl.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/browser/indexed_db/mock_indexed_db_callbacks.h" #include "content/browser/indexed_db/mock_indexed_db_database_callbacks.h" #include "content/public/browser/storage_partition.h" @@ -31,6 +32,37 @@ using url::Origin; namespace content { +namespace { + +class LevelDBLock { + public: + LevelDBLock() : env_(nullptr), lock_(nullptr) {} + LevelDBLock(leveldb::Env* env, leveldb::FileLock* lock) + : env_(env), lock_(lock) {} + ~LevelDBLock() { + if (env_) + env_->UnlockFile(lock_); + } + + private: + leveldb::Env* env_; + leveldb::FileLock* lock_; + + DISALLOW_COPY_AND_ASSIGN(LevelDBLock); +}; + +std::unique_ptr<LevelDBLock> LockForTesting(const base::FilePath& file_name) { + leveldb::Env* env = LevelDBEnv::Get(); + base::FilePath lock_path = file_name.AppendASCII("LOCK"); + leveldb::FileLock* lock = nullptr; + leveldb::Status status = env->LockFile(lock_path.AsUTF8Unsafe(), &lock); + if (!status.ok()) + return std::unique_ptr<LevelDBLock>(); + DCHECK(lock); + return std::make_unique<LevelDBLock>(env, lock); +} + +} // namespace class IndexedDBTest : public testing::Test { public: @@ -69,7 +101,7 @@ auto idb_context = base::MakeRefCounted<IndexedDBContextImpl>( temp_dir.GetPath(), special_storage_policy_.get(), - quota_manager_proxy_.get()); + quota_manager_proxy_.get(), indexed_db::GetDefaultLevelDBFactory()); normal_path = idb_context->GetFilePathForTesting(kNormalOrigin); session_only_path = idb_context->GetFilePathForTesting(kSessionOnlyOrigin); @@ -99,7 +131,7 @@ // With the levelDB backend, these are directories. auto idb_context = base::MakeRefCounted<IndexedDBContextImpl>( temp_dir.GetPath(), special_storage_policy_.get(), - quota_manager_proxy_.get()); + quota_manager_proxy_.get(), indexed_db::GetDefaultLevelDBFactory()); // Save session state. This should bypass the destruction-time deletion. idb_context->SetForceKeepSessionState(); @@ -153,7 +185,7 @@ auto idb_context = base::MakeRefCounted<IndexedDBContextImpl>( temp_dir.GetPath(), special_storage_policy_.get(), - quota_manager_proxy_.get()); + quota_manager_proxy_.get(), indexed_db::GetDefaultLevelDBFactory()); const Origin kTestOrigin = Origin::Create(GURL("http://test/")); @@ -210,12 +242,12 @@ auto idb_context = base::MakeRefCounted<IndexedDBContextImpl>( temp_dir.GetPath(), special_storage_policy_.get(), - quota_manager_proxy_.get()); + quota_manager_proxy_.get(), indexed_db::GetDefaultLevelDBFactory()); base::FilePath test_path = idb_context->GetFilePathForTesting(kTestOrigin); ASSERT_TRUE(base::CreateDirectory(test_path)); - auto lock = LevelDBDatabase::LockForTesting(test_path); + auto lock = LockForTesting(test_path); ASSERT_TRUE(lock); base::RunLoop loop; @@ -235,7 +267,7 @@ auto idb_context = base::MakeRefCounted<IndexedDBContextImpl>( temp_dir.GetPath(), special_storage_policy_.get(), - quota_manager_proxy_.get()); + quota_manager_proxy_.get(), indexed_db::GetDefaultLevelDBFactory()); auto temp_path = temp_dir.GetPath(); auto callbacks = base::MakeRefCounted<MockIndexedDBCallbacks>();
diff --git a/content/browser/indexed_db/leveldb/fake_leveldb_factory.cc b/content/browser/indexed_db/leveldb/fake_leveldb_factory.cc new file mode 100644 index 0000000..baf374a --- /dev/null +++ b/content/browser/indexed_db/leveldb/fake_leveldb_factory.cc
@@ -0,0 +1,101 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/indexed_db/leveldb/fake_leveldb_factory.h" + +#include "base/memory/ptr_util.h" +#include "content/browser/indexed_db/indexed_db_leveldb_operations.h" +#include "third_party/leveldatabase/src/include/leveldb/db.h" +#include "third_party/leveldatabase/src/include/leveldb/slice.h" +#include "third_party/leveldatabase/src/include/leveldb/status.h" + +namespace content { +namespace indexed_db { +namespace { + +// BrokenDB is a fake leveldb::DB that will return a given error status on every +// method call, or no-op if there is nothing to return. +class BrokenDB : public leveldb::DB { + public: + BrokenDB(leveldb::Status returned_status) + : returned_status_(std::move(returned_status)) {} + ~BrokenDB() override {} + + // Implementations of the DB interface + leveldb::Status Put(const leveldb::WriteOptions&, + const leveldb::Slice& key, + const leveldb::Slice& value) override { + return returned_status_; + } + leveldb::Status Delete(const leveldb::WriteOptions&, + const leveldb::Slice& key) override { + return returned_status_; + } + leveldb::Status Write(const leveldb::WriteOptions& options, + leveldb::WriteBatch* updates) override { + return returned_status_; + } + leveldb::Status Get(const leveldb::ReadOptions& options, + const leveldb::Slice& key, + std::string* value) override { + return returned_status_; + } + leveldb::Iterator* NewIterator(const leveldb::ReadOptions&) override { + return nullptr; + } + const leveldb::Snapshot* GetSnapshot() override { return nullptr; } + void ReleaseSnapshot(const leveldb::Snapshot* snapshot) override {} + bool GetProperty(const leveldb::Slice& property, + std::string* value) override { + return false; + } + void GetApproximateSizes(const leveldb::Range* range, + int n, + uint64_t* sizes) override {} + void CompactRange(const leveldb::Slice* begin, + const leveldb::Slice* end) override {} + + private: + leveldb::Status returned_status_; +}; + +} // namespace + +FakeLevelDBFactory::FakeLevelDBFactory() = default; +FakeLevelDBFactory::~FakeLevelDBFactory() {} + +// static +scoped_refptr<LevelDBState> FakeLevelDBFactory::GetBrokenLevelDB( + leveldb::Status error_to_return, + const base::FilePath& reported_file_path) { + return LevelDBState::CreateForDiskDB( + indexed_db::GetDefaultLevelDBComparator(), + indexed_db::GetDefaultIndexedDBComparator(), + std::make_unique<BrokenDB>(error_to_return), reported_file_path); +} + +void FakeLevelDBFactory::EnqueueNextOpenLevelDBResult( + scoped_refptr<LevelDBState> state, + leveldb::Status status, + bool is_disk_full) { + next_leveldb_states_.push( + std::make_tuple(std::move(state), status, is_disk_full)); +} + +std::tuple<scoped_refptr<LevelDBState>, leveldb::Status, bool /*disk_full*/> +FakeLevelDBFactory::OpenLevelDB( + const base::FilePath& file_name, + const LevelDBComparator* idb_comparator, + const leveldb::Comparator* ldb_comparator) const { + if (next_leveldb_states_.empty()) { + return DefaultLevelDBFactory::OpenLevelDB(file_name, idb_comparator, + ldb_comparator); + } + auto tuple = std::move(next_leveldb_states_.front()); + next_leveldb_states_.pop(); + return tuple; +} + +} // namespace indexed_db +} // namespace content
diff --git a/content/browser/indexed_db/leveldb/fake_leveldb_factory.h b/content/browser/indexed_db/leveldb/fake_leveldb_factory.h new file mode 100644 index 0000000..9f21b63 --- /dev/null +++ b/content/browser/indexed_db/leveldb/fake_leveldb_factory.h
@@ -0,0 +1,47 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_INDEXED_DB_LEVELDB_FAKE_LEVELDB_FACTORY_H_ +#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_FAKE_LEVELDB_FACTORY_H_ + +#include <queue> +#include <utility> + +#include "content/browser/indexed_db/leveldb/leveldb_env.h" + +namespace content { +namespace indexed_db { + +// Used for unittests, this factory will only create in-memory leveldb +// databases, and will optionally allow the user to override the next +// LevelDBState returned with |EnqueueNextLevelDBState|. +class FakeLevelDBFactory : public DefaultLevelDBFactory { + public: + FakeLevelDBFactory(); + ~FakeLevelDBFactory() override; + + static scoped_refptr<LevelDBState> GetBrokenLevelDB( + leveldb::Status error_to_return, + const base::FilePath& reported_file_path); + + void EnqueueNextOpenLevelDBResult(scoped_refptr<LevelDBState> state, + leveldb::Status status, + bool is_disk_full); + + std::tuple<scoped_refptr<LevelDBState>, leveldb::Status, bool /*disk_full*/> + OpenLevelDB(const base::FilePath& file_name, + const LevelDBComparator* idb_comparator, + const leveldb::Comparator* ldb_comparator) const override; + + private: + mutable std::queue<std::tuple<scoped_refptr<LevelDBState>, + leveldb::Status, + bool /*disk_full*/>> + next_leveldb_states_; +}; + +} // namespace indexed_db +} // namespace content + +#endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_FAKE_LEVELDB_FACTORY_H_
diff --git a/content/browser/indexed_db/leveldb/leveldb_comparator.cc b/content/browser/indexed_db/leveldb/leveldb_comparator.cc new file mode 100644 index 0000000..6eb3d2a6 --- /dev/null +++ b/content/browser/indexed_db/leveldb/leveldb_comparator.cc
@@ -0,0 +1,52 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/indexed_db/leveldb/leveldb_comparator.h" + +#include <utility> + +#include "base/no_destructor.h" +#include "base/strings/string_piece.h" +#include "third_party/leveldatabase/env_chromium.h" +#include "third_party/leveldatabase/src/include/leveldb/slice.h" + +namespace content { +namespace { + +// Adapter from the leveldb::Slice comparator version to the base::StringPiece +// version. +class LevelDBComparatorToIDBComparator : public LevelDBComparator { + public: + explicit LevelDBComparatorToIDBComparator( + const leveldb::Comparator* comparator) + : comparator_(comparator) {} + + int Compare(const base::StringPiece& a, + const base::StringPiece& b) const override { + return comparator_->Compare(leveldb_env::MakeSlice(a), + leveldb_env::MakeSlice(b)); + } + const char* Name() const override { return comparator_->Name(); } + void FindShortestSeparator(std::string* start, + const base::StringPiece& limit) const override { + comparator_->FindShortestSeparator(start, leveldb_env::MakeSlice(limit)); + } + void FindShortSuccessor(std::string* key) const override { + comparator_->FindShortSuccessor(key); + } + + private: + const leveldb::Comparator* comparator_; +}; + +} // namespace + +// static +const LevelDBComparator* LevelDBComparator::BytewiseComparator() { + static const base::NoDestructor<LevelDBComparatorToIDBComparator> + idb_comparator(leveldb::BytewiseComparator()); + return idb_comparator.get(); +} + +} // namespace content
diff --git a/content/browser/indexed_db/leveldb/leveldb_comparator.h b/content/browser/indexed_db/leveldb/leveldb_comparator.h index aac8808..3af7052 100644 --- a/content/browser/indexed_db/leveldb/leveldb_comparator.h +++ b/content/browser/indexed_db/leveldb/leveldb_comparator.h
@@ -5,18 +5,29 @@ #ifndef CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_COMPARATOR_H_ #define CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_COMPARATOR_H_ +#include <memory> + #include "base/strings/string_piece.h" #include "content/common/content_export.h" +#include "third_party/leveldatabase/src/include/leveldb/comparator.h" namespace content { class CONTENT_EXPORT LevelDBComparator { public: + // Returns a global singleton bytewise comparator. + static const LevelDBComparator* BytewiseComparator(); + virtual ~LevelDBComparator() {} virtual int Compare(const base::StringPiece& a, const base::StringPiece& b) const = 0; virtual const char* Name() const = 0; + + // TODO(dmurph): Support the methods below in the future. + virtual void FindShortestSeparator(std::string* start, + const base::StringPiece& limit) const {} + virtual void FindShortSuccessor(std::string* key) const {} }; } // namespace content
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.cc b/content/browser/indexed_db/leveldb/leveldb_database.cc index 65e8dd55..96ca28b 100644 --- a/content/browser/indexed_db/leveldb/leveldb_database.cc +++ b/content/browser/indexed_db/leveldb/leveldb_database.cc
@@ -28,6 +28,7 @@ #include "base/trace_event/process_memory_dump.h" #include "build/build_config.h" #include "content/browser/indexed_db/indexed_db_class_factory.h" +#include "content/browser/indexed_db/indexed_db_reporting.h" #include "content/browser/indexed_db/indexed_db_tracing.h" #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" #include "content/browser/indexed_db/leveldb/leveldb_env.h" @@ -36,7 +37,6 @@ #include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/leveldb_chrome.h" #include "third_party/leveldatabase/src/include/leveldb/db.h" -#include "third_party/leveldatabase/src/include/leveldb/filter_policy.h" #include "third_party/leveldatabase/src/include/leveldb/slice.h" using base::StringPiece; @@ -61,186 +61,31 @@ // See http://crbug.com/338385. const bool kSyncWrites = true; #endif - -class LockImpl : public LevelDBLock { - public: - explicit LockImpl(leveldb::Env* env, leveldb::FileLock* lock) - : env_(env), lock_(lock) {} - ~LockImpl() override { env_->UnlockFile(lock_); } - - private: - leveldb::Env* env_; - leveldb::FileLock* lock_; - - DISALLOW_COPY_AND_ASSIGN(LockImpl); -}; - -class ComparatorAdapter : public leveldb::Comparator { - public: - explicit ComparatorAdapter(const LevelDBComparator* comparator) - : comparator_(comparator) {} - - int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const override { - return comparator_->Compare(leveldb_env::MakeStringPiece(a), - leveldb_env::MakeStringPiece(b)); - } - - const char* Name() const override { return comparator_->Name(); } - - // TODO(jsbell): Support the methods below in the future. - void FindShortestSeparator(std::string* start, - const leveldb::Slice& limit) const override {} - - void FindShortSuccessor(std::string* key) const override {} - - private: - const LevelDBComparator* comparator_; -}; - -leveldb::Status OpenDB( - leveldb::Comparator* comparator, - leveldb::Env* env, - const base::FilePath& path, - std::unique_ptr<leveldb::DB>* db, - std::unique_ptr<const leveldb::FilterPolicy>* filter_policy) { - filter_policy->reset(leveldb::NewBloomFilterPolicy(10)); - leveldb_env::Options options; - options.comparator = comparator; - options.create_if_missing = true; - options.paranoid_checks = true; - options.filter_policy = filter_policy->get(); - options.compression = leveldb::kSnappyCompression; - options.write_buffer_size = - leveldb_env::WriteBufferSize(base::SysInfo::AmountOfTotalDiskSpace(path)); - - // For info about the troubles we've run into with this parameter, see: - // https://code.google.com/p/chromium/issues/detail?id=227313#c11 - options.max_open_files = 80; - options.env = env; - options.block_cache = leveldb_chrome::GetSharedWebBlockCache(); - - // ChromiumEnv assumes UTF8, converts back to FilePath before using. - return leveldb_env::OpenDB(options, path.AsUTF8Unsafe(), db); -} - -int CheckFreeSpace(const char* const type, const base::FilePath& file_name) { - std::string name = - std::string("WebCore.IndexedDB.LevelDB.Open") + type + "FreeDiskSpace"; - int64_t free_disk_space_in_k_bytes = - base::SysInfo::AmountOfFreeDiskSpace(file_name) / 1024; - if (free_disk_space_in_k_bytes < 0) { - base::Histogram::FactoryGet( - "WebCore.IndexedDB.LevelDB.FreeDiskSpaceFailure", - 1, - 2 /*boundary*/, - 2 /*boundary*/ + 1, - base::HistogramBase::kUmaTargetedHistogramFlag)->Add(1 /*sample*/); - return -1; - } - int clamped_disk_space_k_bytes = free_disk_space_in_k_bytes > INT_MAX - ? INT_MAX - : free_disk_space_in_k_bytes; - const uint64_t histogram_max = static_cast<uint64_t>(1e9); - static_assert(histogram_max <= INT_MAX, "histogram_max too big"); - base::Histogram::FactoryGet(name, - 1, - histogram_max, - 11 /*buckets*/, - base::HistogramBase::kUmaTargetedHistogramFlag) - ->Add(clamped_disk_space_k_bytes); - return clamped_disk_space_k_bytes; -} - -void ParseAndHistogramIOErrorDetails(const std::string& histogram_name, - const leveldb::Status& s) { - leveldb_env::MethodID method; - base::File::Error error = base::File::FILE_OK; - leveldb_env::ErrorParsingResult result = - leveldb_env::ParseMethodAndError(s, &method, &error); - if (result == leveldb_env::NONE) - return; - std::string method_histogram_name(histogram_name); - method_histogram_name.append(".EnvMethod"); - base::LinearHistogram::FactoryGet( - method_histogram_name, - 1, - leveldb_env::kNumEntries, - leveldb_env::kNumEntries + 1, - base::HistogramBase::kUmaTargetedHistogramFlag)->Add(method); - - std::string error_histogram_name(histogram_name); - - if (result == leveldb_env::METHOD_AND_BFE) { - DCHECK_LT(error, 0); - error_histogram_name.append(std::string(".BFE.") + - leveldb_env::MethodIDToString(method)); - base::LinearHistogram::FactoryGet( - error_histogram_name, - 1, - -base::File::FILE_ERROR_MAX, - -base::File::FILE_ERROR_MAX + 1, - base::HistogramBase::kUmaTargetedHistogramFlag)->Add(-error); - } -} - -void ParseAndHistogramCorruptionDetails(const std::string& histogram_name, - const leveldb::Status& status) { - int error = leveldb_env::GetCorruptionCode(status); - DCHECK_GE(error, 0); - std::string corruption_histogram_name(histogram_name); - corruption_histogram_name.append(".Corruption"); - const int kNumPatterns = leveldb_env::GetNumCorruptionCodes(); - base::LinearHistogram::FactoryGet( - corruption_histogram_name, - 1, - kNumPatterns, - kNumPatterns + 1, - base::HistogramBase::kUmaTargetedHistogramFlag)->Add(error); -} - -void HistogramLevelDBError(const std::string& histogram_name, - const leveldb::Status& s) { - if (s.ok()) { - NOTREACHED(); - return; - } - enum { - LEVEL_DB_NOT_FOUND, - LEVEL_DB_CORRUPTION, - LEVEL_DB_IO_ERROR, - LEVEL_DB_OTHER, - LEVEL_DB_MAX_ERROR - }; - int leveldb_error = LEVEL_DB_OTHER; - if (s.IsNotFound()) - leveldb_error = LEVEL_DB_NOT_FOUND; - else if (s.IsCorruption()) - leveldb_error = LEVEL_DB_CORRUPTION; - else if (s.IsIOError()) - leveldb_error = LEVEL_DB_IO_ERROR; - base::Histogram::FactoryGet(histogram_name, - 1, - LEVEL_DB_MAX_ERROR, - LEVEL_DB_MAX_ERROR + 1, - base::HistogramBase::kUmaTargetedHistogramFlag) - ->Add(leveldb_error); - if (s.IsIOError()) - ParseAndHistogramIOErrorDetails(histogram_name, s); - else - ParseAndHistogramCorruptionDetails(histogram_name, s); -} - } // namespace LevelDBSnapshot::LevelDBSnapshot(LevelDBDatabase* db) - : db_(db->db_.get()), snapshot_(db_->GetSnapshot()) {} + : db_(db->db()), snapshot_(db_->GetSnapshot()) {} LevelDBSnapshot::~LevelDBSnapshot() { db_->ReleaseSnapshot(snapshot_); } -LevelDBDatabase::LevelDBDatabase(size_t max_open_iterators) - : clock_(new base::DefaultClock()), iterator_lru_(max_open_iterators) { +// static +constexpr const size_t LevelDBDatabase::kDefaultMaxOpenIteratorsPerDatabase; + +LevelDBDatabase::LevelDBDatabase( + scoped_refptr<LevelDBState> level_db_state, + scoped_refptr<base::SequencedTaskRunner> task_runner, + size_t max_open_iterators) + : level_db_state_(std::move(level_db_state)), + clock_(new base::DefaultClock()), + iterator_lru_(max_open_iterators) { + if (task_runner) { + base::trace_event::MemoryDumpManager::GetInstance() + ->RegisterDumpProviderWithSequencedTaskRunner( + this, "IndexedDBBackingStore", std::move(task_runner), + base::trace_event::MemoryDumpProvider::Options()); + } DCHECK(max_open_iterators); } @@ -249,118 +94,6 @@ max_iterators_); base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider( this); - // db_'s destructor uses comparator_adapter_; order of deletion is important. - CloseDatabase(); - comparator_adapter_.reset(); - env_.reset(); -} - -void LevelDBDatabase::CloseDatabase() { - if (db_) { - base::TimeTicks begin_time = base::TimeTicks::Now(); - db_.reset(); - UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.CloseTime", - base::TimeTicks::Now() - begin_time); - } -} - -// static -leveldb::Status LevelDBDatabase::Destroy(const base::FilePath& file_name) { - leveldb_env::Options options; - options.env = LevelDBEnv::Get(); - // ChromiumEnv assumes UTF8, converts back to FilePath before using. - return leveldb::DestroyDB(file_name.AsUTF8Unsafe(), options); -} - -// static -std::unique_ptr<LevelDBLock> LevelDBDatabase::LockForTesting( - const base::FilePath& file_name) { - leveldb::Env* env = LevelDBEnv::Get(); - base::FilePath lock_path = file_name.AppendASCII("LOCK"); - leveldb::FileLock* lock = nullptr; - leveldb::Status status = env->LockFile(lock_path.AsUTF8Unsafe(), &lock); - if (!status.ok()) - return std::unique_ptr<LevelDBLock>(); - DCHECK(lock); - return std::make_unique<LockImpl>(env, lock); -} - -// static -leveldb::Status LevelDBDatabase::Open(const base::FilePath& file_name, - const LevelDBComparator* comparator, - size_t max_open_cursors, - std::unique_ptr<LevelDBDatabase>* result, - bool* is_disk_full) { - IDB_TRACE("LevelDBDatabase::Open"); - base::TimeTicks begin_time = base::TimeTicks::Now(); - - std::unique_ptr<ComparatorAdapter> comparator_adapter( - std::make_unique<ComparatorAdapter>(comparator)); - - std::unique_ptr<leveldb::DB> db; - std::unique_ptr<const leveldb::FilterPolicy> filter_policy; - const leveldb::Status s = OpenDB(comparator_adapter.get(), LevelDBEnv::Get(), - file_name, &db, &filter_policy); - - if (!s.ok()) { - HistogramLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", s); - int free_space_k_bytes = CheckFreeSpace("Failure", file_name); - // Disks with <100k of free space almost never succeed in opening a - // leveldb database. - if (is_disk_full) - *is_disk_full = free_space_k_bytes >= 0 && free_space_k_bytes < 100; - - LOG(ERROR) << "Failed to open LevelDB database from " - << file_name.AsUTF8Unsafe() << "," << s.ToString(); - return s; - } - - UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime", - base::TimeTicks::Now() - begin_time); - - CheckFreeSpace("Success", file_name); - - (*result) = base::WrapUnique(new LevelDBDatabase(max_open_cursors)); - (*result)->db_ = std::move(db); - (*result)->comparator_adapter_ = std::move(comparator_adapter); - (*result)->comparator_ = comparator; - (*result)->filter_policy_ = std::move(filter_policy); - (*result)->file_name_for_tracing = file_name.BaseName().AsUTF8Unsafe(); - - return s; -} - -// static -std::unique_ptr<LevelDBDatabase> LevelDBDatabase::OpenInMemory( - const LevelDBComparator* comparator) { - std::unique_ptr<ComparatorAdapter> comparator_adapter( - std::make_unique<ComparatorAdapter>(comparator)); - std::unique_ptr<leveldb::Env> in_memory_env( - leveldb_chrome::NewMemEnv("indexed-db", LevelDBEnv::Get())); - - std::unique_ptr<leveldb::DB> db; - std::unique_ptr<const leveldb::FilterPolicy> filter_policy; - const leveldb::Status s = OpenDB(comparator_adapter.get(), - in_memory_env.get(), - base::FilePath(), - &db, - &filter_policy); - - if (!s.ok()) { - LOG(ERROR) << "Failed to open in-memory LevelDB database: " << s.ToString(); - return std::unique_ptr<LevelDBDatabase>(); - } - - std::unique_ptr<LevelDBDatabase> result = base::WrapUnique( - new LevelDBDatabase(kDefaultMaxOpenIteratorsPerDatabase)); - result->env_ = std::move(in_memory_env); - result->db_ = std::move(db); - result->comparator_adapter_ = std::move(comparator_adapter); - result->comparator_ = comparator; - result->filter_policy_ = std::move(filter_policy); - result->file_name_for_tracing = "in-memory-database"; - - return result; } leveldb::Status LevelDBDatabase::Put(const StringPiece& key, @@ -370,8 +103,9 @@ leveldb::WriteOptions write_options; write_options.sync = kSyncWrites; - const leveldb::Status s = db_->Put(write_options, leveldb_env::MakeSlice(key), - leveldb_env::MakeSlice(*value)); + const leveldb::Status s = + db()->Put(write_options, leveldb_env::MakeSlice(key), + leveldb_env::MakeSlice(*value)); if (!s.ok()) LOG(ERROR) << "LevelDB put failed: " << s.ToString(); else @@ -386,7 +120,7 @@ write_options.sync = kSyncWrites; const leveldb::Status s = - db_->Delete(write_options, leveldb_env::MakeSlice(key)); + db()->Delete(write_options, leveldb_env::MakeSlice(key)); if (!s.ok() && !s.IsNotFound()) LOG(ERROR) << "LevelDB remove failed: " << s.ToString(); last_modified_ = clock_->Now(); @@ -404,14 +138,14 @@ read_options.snapshot = snapshot ? snapshot->snapshot_ : nullptr; const leveldb::Status s = - db_->Get(read_options, leveldb_env::MakeSlice(key), value); + db()->Get(read_options, leveldb_env::MakeSlice(key), value); if (s.ok()) { *found = true; return s; } if (s.IsNotFound()) return leveldb::Status::OK(); - HistogramLevelDBError("WebCore.IndexedDB.LevelDBReadErrors", s); + indexed_db::ReportLevelDBError("WebCore.IndexedDB.LevelDBReadErrors", s); LOG(ERROR) << "LevelDB get failed: " << s.ToString(); return s; } @@ -422,9 +156,9 @@ write_options.sync = kSyncWrites; const leveldb::Status s = - db_->Write(write_options, write_batch.write_batch_.get()); + db()->Write(write_options, write_batch.write_batch_.get()); if (!s.ok()) { - HistogramLevelDBError("WebCore.IndexedDB.LevelDBWriteErrors", s); + indexed_db::ReportLevelDBError("WebCore.IndexedDB.LevelDBWriteErrors", s); LOG(ERROR) << "LevelDB write failed: " << s.ToString(); } else { UMA_HISTOGRAM_TIMES("WebCore.IndexedDB.LevelDB.WriteTime", @@ -440,28 +174,24 @@ max_iterators_ = std::max(max_iterators_, num_iterators_); // Iterator isn't added to lru cache until it is used, as memory isn't loaded // for the iterator until it's first Seek call. - std::unique_ptr<leveldb::Iterator> i(db_->NewIterator(options)); + std::unique_ptr<leveldb::Iterator> i(db()->NewIterator(options)); return std::unique_ptr<LevelDBIterator>( IndexedDBClassFactory::Get()->CreateIteratorImpl(std::move(i), this, options.snapshot)); } -const LevelDBComparator* LevelDBDatabase::Comparator() const { - return comparator_; -} - void LevelDBDatabase::Compact(const base::StringPiece& start, const base::StringPiece& stop) { IDB_TRACE("LevelDBDatabase::Compact"); const leveldb::Slice start_slice = leveldb_env::MakeSlice(start); const leveldb::Slice stop_slice = leveldb_env::MakeSlice(stop); // NULL batch means just wait for earlier writes to be done - db_->Write(leveldb::WriteOptions(), nullptr); - db_->CompactRange(&start_slice, &stop_slice); + db()->Write(leveldb::WriteOptions(), nullptr); + db()->CompactRange(&start_slice, &stop_slice); } void LevelDBDatabase::CompactAll() { - db_->CompactRange(nullptr, nullptr); + db()->CompactRange(nullptr, nullptr); } leveldb::ReadOptions LevelDBDatabase::DefaultReadOptions() { @@ -480,31 +210,30 @@ bool LevelDBDatabase::OnMemoryDump( const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) { - if (!db_) + if (!level_db_state_) return false; // All leveldb databases are already dumped by leveldb_env::DBTracker. Add // an edge to the existing database. auto* db_tracker_dump = - leveldb_env::DBTracker::GetOrCreateAllocatorDump(pmd, db_.get()); + leveldb_env::DBTracker::GetOrCreateAllocatorDump(pmd, db()); if (!db_tracker_dump) return true; auto* db_dump = pmd->CreateAllocatorDump( base::StringPrintf("site_storage/index_db/db_0x%" PRIXPTR, - reinterpret_cast<uintptr_t>(db_.get()))); + reinterpret_cast<uintptr_t>(db()))); db_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, base::trace_event::MemoryAllocatorDump::kUnitsBytes, db_tracker_dump->GetSizeInternal()); pmd->AddOwnershipEdge(db_dump->guid(), db_tracker_dump->guid()); - if (env_ && leveldb_chrome::IsMemEnv(env_.get())) { + if (env() && leveldb_chrome::IsMemEnv(env())) { // All leveldb env's are already dumped by leveldb_env::DBTracker. Add // an edge to the existing env. - auto* env_tracker_dump = - DBTracker::GetOrCreateAllocatorDump(pmd, env_.get()); + auto* env_tracker_dump = DBTracker::GetOrCreateAllocatorDump(pmd, env()); auto* env_dump = pmd->CreateAllocatorDump( base::StringPrintf("site_storage/index_db/memenv_0x%" PRIXPTR, - reinterpret_cast<uintptr_t>(env_.get()))); + reinterpret_cast<uintptr_t>(env()))); env_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize, base::trace_event::MemoryAllocatorDump::kUnitsBytes, env_tracker_dump->GetSizeInternal()); @@ -532,7 +261,7 @@ leveldb::ReadOptions read_options; read_options.verify_checksums = true; read_options.snapshot = snapshot; - return std::unique_ptr<leveldb::Iterator>(db_->NewIterator(read_options)); + return base::WrapUnique(db()->NewIterator(read_options)); } LevelDBDatabase::DetachIteratorOnDestruct::~DetachIteratorOnDestruct() {
diff --git a/content/browser/indexed_db/leveldb/leveldb_database.h b/content/browser/indexed_db/leveldb/leveldb_database.h index 56bf775..516a8a15 100644 --- a/content/browser/indexed_db/leveldb/leveldb_database.h +++ b/content/browser/indexed_db/leveldb/leveldb_database.h
@@ -12,10 +12,12 @@ #include "base/files/file_path.h" #include "base/gtest_prod_util.h" #include "base/macros.h" +#include "base/sequenced_task_runner.h" #include "base/strings/string16.h" #include "base/strings/string_piece.h" #include "base/time/clock.h" #include "base/trace_event/memory_dump_provider.h" +#include "content/browser/indexed_db/scopes/leveldb_state.h" #include "content/common/content_export.h" #include "third_party/leveldatabase/src/include/leveldb/comparator.h" #include "third_party/leveldatabase/src/include/leveldb/options.h" @@ -24,7 +26,6 @@ namespace leveldb { class Comparator; class DB; -class FilterPolicy; class Iterator; class Env; class Snapshot; @@ -51,15 +52,6 @@ DISALLOW_COPY_AND_ASSIGN(LevelDBSnapshot); }; -class CONTENT_EXPORT LevelDBLock { - public: - LevelDBLock() {} - virtual ~LevelDBLock() {} - - private: - DISALLOW_COPY_AND_ASSIGN(LevelDBLock); -}; - class CONTENT_EXPORT LevelDBDatabase : public base::trace_event::MemoryDumpProvider { public: @@ -68,15 +60,11 @@ static const size_t kDefaultMaxOpenIteratorsPerDatabase = 50; // |max_open_cursors| cannot be 0. - static leveldb::Status Open(const base::FilePath& file_name, - const LevelDBComparator* comparator, - size_t max_open_cursors, - std::unique_ptr<LevelDBDatabase>* db, - bool* is_disk_full = 0); + // All calls to this class should be done on |task_runner|. + LevelDBDatabase(scoped_refptr<LevelDBState> level_db_state, + scoped_refptr<base::SequencedTaskRunner> task_runner, + size_t max_open_iterators); - static std::unique_ptr<LevelDBDatabase> OpenInMemory( - const LevelDBComparator* comparator); - static leveldb::Status Destroy(const base::FilePath& file_name); ~LevelDBDatabase() override; leveldb::Status Put(const base::StringPiece& key, std::string* value); @@ -89,7 +77,9 @@ // Note: Use DefaultReadOptions() and then adjust any values afterwards. std::unique_ptr<LevelDBIterator> CreateIterator( const leveldb::ReadOptions& options); - const LevelDBComparator* Comparator() const; + const LevelDBComparator* Comparator() const { + return level_db_state_->idb_comparator(); + } void Compact(const base::StringPiece& start, const base::StringPiece& stop); void CompactAll(); @@ -100,23 +90,17 @@ bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args, base::trace_event::ProcessMemoryDump* pmd) override; - leveldb::DB* db() { return db_.get(); } - leveldb::Env* env() { return env_.get(); } + leveldb::DB* db() { return level_db_state_->db(); } + leveldb::Env* env() { return level_db_state_->in_memory_env(); } base::Time LastModified() const { return last_modified_; } void SetClockForTesting(std::unique_ptr<base::Clock> clock); - protected: - explicit LevelDBDatabase(size_t max_open_iterators); - private: friend class LevelDBSnapshot; friend class LevelDBIteratorImpl; FRIEND_TEST_ALL_PREFIXES(IndexedDBTest, DeleteFailsIfDirectoryLocked); - static std::unique_ptr<LevelDBLock> LockForTesting( - const base::FilePath& file_name); - // Methods for iterator pooling. std::unique_ptr<leveldb::Iterator> CreateLevelDBIterator( const leveldb::Snapshot*); @@ -125,11 +109,7 @@ void CloseDatabase(); - std::unique_ptr<leveldb::Env> env_; - std::unique_ptr<leveldb::Comparator> comparator_adapter_; - std::unique_ptr<leveldb::DB> db_; - std::unique_ptr<const leveldb::FilterPolicy> filter_policy_; - const LevelDBComparator* comparator_; + scoped_refptr<LevelDBState> level_db_state_; base::Time last_modified_; std::unique_ptr<base::Clock> clock_;
diff --git a/content/browser/indexed_db/leveldb/leveldb_env.cc b/content/browser/indexed_db/leveldb/leveldb_env.cc index cdb0a89..f61b8bb 100644 --- a/content/browser/indexed_db/leveldb/leveldb_env.cc +++ b/content/browser/indexed_db/leveldb/leveldb_env.cc
@@ -4,15 +4,45 @@ #include "content/browser/indexed_db/leveldb/leveldb_env.h" +#include "base/files/file_util.h" +#include "base/metrics/histogram_macros.h" +#include "base/no_destructor.h" +#include "base/system/sys_info.h" +#include "content/browser/indexed_db/indexed_db_leveldb_operations.h" +#include "content/browser/indexed_db/indexed_db_reporting.h" +#include "content/browser/indexed_db/indexed_db_tracing.h" +#include "third_party/leveldatabase/leveldb_chrome.h" +#include "third_party/leveldatabase/src/include/leveldb/filter_policy.h" + +namespace content { namespace { // Static member initialization. base::LazyInstance<content::LevelDBEnv>::Leaky g_leveldb_env = LAZY_INSTANCE_INITIALIZER; -} // namespace +leveldb_env::Options GetLevelDBOptions(leveldb::Env* env, + const leveldb::Comparator* comparator, + size_t write_buffer_size, + bool paranoid_checks) { + static const leveldb::FilterPolicy* kIDBFilterPolicy = + leveldb::NewBloomFilterPolicy(10); + leveldb_env::Options options; + options.comparator = comparator; + options.create_if_missing = true; + options.paranoid_checks = paranoid_checks; + options.filter_policy = kIDBFilterPolicy; + options.compression = leveldb::kSnappyCompression; + options.write_buffer_size = write_buffer_size; + // For info about the troubles we've run into with this parameter, see: + // https://crbug.com/227313#c11 + options.max_open_files = 80; + options.env = env; + options.block_cache = leveldb_chrome::GetSharedWebBlockCache(); + return options; +} -namespace content { +} // namespace LevelDBEnv::LevelDBEnv() : ChromiumEnv("LevelDBEnv.IDB") {} @@ -20,4 +50,112 @@ return g_leveldb_env.Pointer(); } +namespace indexed_db { + +std::tuple<scoped_refptr<LevelDBState>, leveldb::Status, bool /* disk_full*/> +DefaultLevelDBFactory::OpenLevelDB( + const base::FilePath& file_name, + const LevelDBComparator* idb_comparator, + const leveldb::Comparator* ldb_comparator) const { + // Please see docs/open_and_verify_leveldb_database.code2flow, and the + // generated pdf (from https://code2flow.com). + // The intended strategy here is to have this function match that flowchart, + // where the flowchart should be seen as the 'master' logic template. Please + // check the git history of both to make sure they are supposed to be in sync. + IDB_TRACE("indexed_db::OpenLDB"); + DCHECK(strcmp(ldb_comparator->Name(), idb_comparator->Name()) == 0); + base::TimeTicks begin_time = base::TimeTicks::Now(); + leveldb::Status status; + std::unique_ptr<leveldb::DB> db; + + if (file_name.empty()) { + std::unique_ptr<leveldb::Env> in_memory_env = + leveldb_chrome::NewMemEnv("indexed-db", LevelDBEnv::Get()); + + constexpr int64_t kBytesInOneMegabyte = 1024 * 1024; + leveldb_env::Options in_memory_options = + GetLevelDBOptions(in_memory_env.get(), ldb_comparator, + /* default of 4MB */ 4 * kBytesInOneMegabyte, + /*paranoid_checks=*/false); + status = leveldb_env::OpenDB(in_memory_options, std::string(), &db); + if (!status.ok()) { + LOG(ERROR) << "Failed to open in-memory LevelDB database: " + << status.ToString(); + // Must match the other returns in this function for RVO. + return {nullptr, status, false}; + } + + return {LevelDBState::CreateForInMemoryDB( + std::move(in_memory_env), ldb_comparator, idb_comparator, + std::move(db), "in-memory-database"), + status, false}; + } + + leveldb_env::Options options = + GetLevelDBOptions(LevelDBEnv::Get(), ldb_comparator, + leveldb_env::WriteBufferSize( + base::SysInfo::AmountOfTotalDiskSpace(file_name)), + /*paranoid_checks=*/true); + + // ChromiumEnv assumes UTF8, converts back to FilePath before using. + status = leveldb_env::OpenDB(options, file_name.AsUTF8Unsafe(), &db); + if (!status.ok()) { + ReportLevelDBError("WebCore.IndexedDB.LevelDBOpenErrors", status); + + constexpr int64_t kBytesInOneKilobyte = 1024; + int64_t free_disk_space_bytes = + base::SysInfo::AmountOfFreeDiskSpace(file_name); + bool below_100kb = free_disk_space_bytes != -1 && + free_disk_space_bytes < 100 * kBytesInOneKilobyte; + + // Disks with <100k of free space almost never succeed in opening a + // leveldb database. + bool is_disk_full = below_100kb || leveldb_env::IndicatesDiskFull(status); + + LOG(ERROR) << "Failed to open LevelDB database from " + << file_name.AsUTF8Unsafe() << "," << status.ToString(); + // Must match the other returns in this function for RVO. + return {nullptr, status, is_disk_full}; + } + + UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.OpenTime", + base::TimeTicks::Now() - begin_time); + + // Must match the other returns in this function for RVO. + return {LevelDBState::CreateForDiskDB(ldb_comparator, idb_comparator, + std::move(db), std::move(file_name)), + status, false}; +} + +leveldb::Status DefaultLevelDBFactory::DestroyLevelDB( + scoped_refptr<LevelDBState> level_db_state) const { + DCHECK(level_db_state); + DCHECK(!level_db_state->in_memory_env() && + !level_db_state->database_path().empty()) + << "Cannot destroy an in-memory databases."; + DCHECK(level_db_state->HasOneRef()) + << "Cannot destroy the database when someone else is keeping the state " + "alive."; + leveldb_env::Options options; + options.env = LevelDBEnv::Get(); + std::string file_path = level_db_state->database_path().AsUTF8Unsafe(); + level_db_state.reset(); + // ChromiumEnv assumes UTF8, converts back to FilePath before using. + return leveldb::DestroyDB(std::move(file_path), options); +} + +leveldb::Status DefaultLevelDBFactory::DestroyLevelDB( + const base::FilePath& path) const { + leveldb_env::Options options; + options.env = LevelDBEnv::Get(); + return leveldb::DestroyDB(path.AsUTF8Unsafe(), options); +} + +// static +DefaultLevelDBFactory* GetDefaultLevelDBFactory() { + static base::NoDestructor<DefaultLevelDBFactory> singleton; + return singleton.get(); +} + +} // namespace indexed_db } // namespace content
diff --git a/content/browser/indexed_db/leveldb/leveldb_env.h b/content/browser/indexed_db/leveldb/leveldb_env.h index 9debbaf..d142c10 100644 --- a/content/browser/indexed_db/leveldb/leveldb_env.h +++ b/content/browser/indexed_db/leveldb/leveldb_env.h
@@ -5,9 +5,18 @@ #ifndef CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_ENV_H_ #define CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_ENV_H_ +#include <tuple> + +#include "base/files/file_path.h" #include "base/lazy_instance.h" +#include "base/memory/scoped_refptr.h" +#include "base/optional.h" +#include "content/browser/indexed_db/leveldb/leveldb_comparator.h" +#include "content/browser/indexed_db/scopes/leveldb_state.h" #include "content/common/content_export.h" #include "third_party/leveldatabase/env_chromium.h" +#include "third_party/leveldatabase/src/include/leveldb/comparator.h" +#include "third_party/leveldatabase/src/include/leveldb/status.h" namespace content { @@ -21,6 +30,51 @@ CONTENT_EXPORT static LevelDBEnv* Get(); }; +namespace indexed_db { + +// Factory class used to open leveldb databases, and stores all necessary +// objects in a LevelDBState. This interface exists so that it can be mocked out +// for tests. +class CONTENT_EXPORT LevelDBFactory { + public: + virtual ~LevelDBFactory() {} + + // Opens a leveldb database with the given comparators and populates it in + // |output_state|. If the |file_name| is empty, then the database will be + // in-memory. The comparator names must match. + virtual std:: + tuple<scoped_refptr<LevelDBState>, leveldb::Status, bool /* disk_full*/> + OpenLevelDB(const base::FilePath& file_name, + const LevelDBComparator* idb_comparator, + const leveldb::Comparator* ldb_comparator) const = 0; + + // A somewhat safe way to destroy a leveldb database. This asserts that there + // are no other references to the given LevelDBState, and deletes the database + // on disk. |level_db_state| must only have one ref. + virtual leveldb::Status DestroyLevelDB( + scoped_refptr<LevelDBState> output_state) const = 0; + + // Assumes that there is no leveldb database currently running for this path. + virtual leveldb::Status DestroyLevelDB(const base::FilePath& path) const = 0; +}; + +class CONTENT_EXPORT DefaultLevelDBFactory : public LevelDBFactory { + public: + DefaultLevelDBFactory() = default; + ~DefaultLevelDBFactory() override {} + std::tuple<scoped_refptr<LevelDBState>, leveldb::Status, bool /* disk_full*/> + OpenLevelDB(const base::FilePath& file_name, + const LevelDBComparator* idb_comparator, + const leveldb::Comparator* ldb_comparator) const override; + leveldb::Status DestroyLevelDB( + scoped_refptr<LevelDBState> output_state) const override; + leveldb::Status DestroyLevelDB(const base::FilePath& path) const override; +}; + +// Returns a singleton default factory. +CONTENT_EXPORT DefaultLevelDBFactory* GetDefaultLevelDBFactory(); + +} // namespace indexed_db } // namespace content #endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_ENV_H_
diff --git a/content/browser/indexed_db/leveldb/leveldb_env_unittest.cc b/content/browser/indexed_db/leveldb/leveldb_env_unittest.cc new file mode 100644 index 0000000..dbec948 --- /dev/null +++ b/content/browser/indexed_db/leveldb/leveldb_env_unittest.cc
@@ -0,0 +1,32 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/indexed_db/leveldb/leveldb_env.h" + +#include <utility> + +#include "base/files/file.h" +#include "base/files/file_path.h" +#include "base/files/scoped_temp_dir.h" +#include "base/optional.h" +#include "content/browser/indexed_db/indexed_db_leveldb_operations.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace content { +namespace indexed_db { +namespace { + +TEST(LevelDBEnvTest, TestInMemory) { + DefaultLevelDBFactory default_factory; + scoped_refptr<LevelDBState> state; + std::tie(state, std::ignore, std::ignore) = default_factory.OpenLevelDB( + base::FilePath(), GetDefaultIndexedDBComparator(), + GetDefaultLevelDBComparator()); + EXPECT_TRUE(state); + EXPECT_TRUE(state->in_memory_env()); +} + +} // namespace +} // namespace indexed_db +} // namespace content
diff --git a/content/browser/indexed_db/leveldb/leveldb_factory.h b/content/browser/indexed_db/leveldb/leveldb_factory.h deleted file mode 100644 index 42fffad..0000000 --- a/content/browser/indexed_db/leveldb/leveldb_factory.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 CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_FACTORY_H_ -#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_FACTORY_H_ - -#include <memory> - -#include "content/common/content_export.h" -#include "third_party/leveldatabase/src/include/leveldb/status.h" - -namespace base { -class FilePath; -} - -namespace content { - -class LevelDBComparator; -class LevelDBDatabase; - -class CONTENT_EXPORT LevelDBFactory { - public: - virtual ~LevelDBFactory() {} - virtual leveldb::Status OpenLevelDB(const base::FilePath& file_name, - const LevelDBComparator* comparator, - std::unique_ptr<LevelDBDatabase>* db, - bool* is_disk_full) = 0; - virtual leveldb::Status DestroyLevelDB(const base::FilePath& file_name) = 0; -}; - -} // namespace content - -#endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_LEVELDB_FACTORY_H_
diff --git a/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc b/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc index 373fe388..ca07c5d7 100644 --- a/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc +++ b/content/browser/indexed_db/leveldb/leveldb_transaction_unittest.cc
@@ -6,11 +6,13 @@ #include <algorithm> #include <cstring> +#include <memory> #include <string> #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" +#include "base/no_destructor.h" #include "base/strings/string_piece.h" #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" #include "content/browser/indexed_db/leveldb/leveldb_database.h" @@ -19,22 +21,12 @@ #include "content/browser/indexed_db/leveldb/leveldb_transaction.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/env_chromium.h" +#include "third_party/leveldatabase/src/include/leveldb/comparator.h" namespace content { namespace { static const size_t kTestingMaxOpenCursors = 3; - -class SimpleComparator : public LevelDBComparator { - public: - int Compare(const base::StringPiece& a, - const base::StringPiece& b) const override { - size_t len = std::min(a.size(), b.size()); - return memcmp(a.begin(), b.begin(), len); - } - const char* Name() const override { return "temp_comparator"; } -}; - } // namespace class LevelDBTransactionTest : public testing::Test { @@ -42,10 +34,17 @@ LevelDBTransactionTest() {} void SetUp() override { ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); - leveldb::Status s = - LevelDBDatabase::Open(temp_directory_.GetPath(), &comparator_, - kTestingMaxOpenCursors, &leveldb_); - ASSERT_TRUE(s.ok()); + scoped_refptr<LevelDBState> ldb_state; + leveldb::Status status; + std::tie(ldb_state, status, std::ignore) = + indexed_db::GetDefaultLevelDBFactory()->OpenLevelDB( + temp_directory_.GetPath(), LevelDBComparator::BytewiseComparator(), + leveldb::BytewiseComparator()); + EXPECT_TRUE(status.ok()); + ASSERT_TRUE(ldb_state); + ASSERT_TRUE(ldb_state->db()); + leveldb_ = std::make_unique<LevelDBDatabase>(std::move(ldb_state), nullptr, + kTestingMaxOpenCursors); ASSERT_TRUE(leveldb_); } void TearDown() override {} @@ -96,7 +95,7 @@ } int Compare(const base::StringPiece& a, const base::StringPiece& b) const { - return comparator_.Compare(a, b); + return leveldb_->Comparator()->Compare(a, b); } LevelDBDatabase* db() { return leveldb_.get(); } @@ -111,7 +110,6 @@ private: base::ScopedTempDir temp_directory_; - SimpleComparator comparator_; std::unique_ptr<LevelDBDatabase> leveldb_; DISALLOW_COPY_AND_ASSIGN(LevelDBTransactionTest);
diff --git a/content/browser/indexed_db/leveldb/leveldb_unittest.cc b/content/browser/indexed_db/leveldb/leveldb_unittest.cc index ea75c48..f569f1a 100644 --- a/content/browser/indexed_db/leveldb/leveldb_unittest.cc +++ b/content/browser/indexed_db/leveldb/leveldb_unittest.cc
@@ -2,15 +2,20 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <content/browser/indexed_db/scopes/leveldb_state.h> #include <stddef.h> #include <algorithm> #include <cstring> #include <string> +#include <tuple> +#include <utility> #include "base/files/file.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_refptr.h" +#include "base/no_destructor.h" #include "base/strings/string_piece.h" #include "base/test/simple_test_clock.h" #include "content/browser/indexed_db/leveldb/leveldb_comparator.h" @@ -20,6 +25,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/leveldb_chrome.h" +#include "third_party/leveldatabase/src/include/leveldb/comparator.h" namespace content { namespace leveldb_unittest { @@ -28,6 +34,10 @@ class SimpleComparator : public LevelDBComparator { public: + static const SimpleComparator* Get() { + static const base::NoDestructor<SimpleComparator> simple_comparator; + return simple_comparator.get(); + } int Compare(const base::StringPiece& a, const base::StringPiece& b) const override { size_t len = std::min(a.size(), b.size()); @@ -36,6 +46,28 @@ const char* Name() const override { return "temp_comparator"; } }; +class SimpleLDBComparator : public leveldb::Comparator { + public: + static const SimpleLDBComparator* Get() { + static const base::NoDestructor<SimpleLDBComparator> simple_ldb_comparator; + return simple_ldb_comparator.get(); + } + int Compare(const leveldb::Slice& a, const leveldb::Slice& b) const override { + size_t len = std::min(a.size(), b.size()); + return memcmp(a.data(), b.data(), len); + } + const char* Name() const override { return "temp_comparator"; } + void FindShortestSeparator(std::string* start, + const leveldb::Slice& limit) const override {} + void FindShortSuccessor(std::string* key) const override {} +}; + +std::tuple<scoped_refptr<LevelDBState>, leveldb::Status, bool /* disk_full*/> +OpenLevelDB(base::FilePath file_name) { + return indexed_db::GetDefaultLevelDBFactory()->OpenLevelDB( + file_name, SimpleComparator::Get(), SimpleLDBComparator::Get()); +} + TEST(LevelDBDatabaseTest, CorruptionTest) { base::ScopedTempDir temp_directory; ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); @@ -44,20 +76,26 @@ const std::string value("value"); std::string put_value; std::string got_value; - SimpleComparator comparator; + scoped_refptr<LevelDBState> ldb_state; + leveldb::Status status; + std::tie(ldb_state, status, std::ignore) = + OpenLevelDB(temp_directory.GetPath()); + EXPECT_TRUE(status.ok()); - std::unique_ptr<LevelDBDatabase> leveldb; - LevelDBDatabase::Open(temp_directory.GetPath(), &comparator, - kDefaultMaxOpenIteratorsPerDatabase, &leveldb); + std::unique_ptr<LevelDBDatabase> leveldb = std::make_unique<LevelDBDatabase>( + std::move(ldb_state), nullptr, kDefaultMaxOpenIteratorsPerDatabase); EXPECT_TRUE(leveldb); put_value = value; - leveldb::Status status = leveldb->Put(key, &put_value); + status = leveldb->Put(key, &put_value); EXPECT_TRUE(status.ok()); leveldb.reset(); EXPECT_FALSE(leveldb); - LevelDBDatabase::Open(temp_directory.GetPath(), &comparator, - kDefaultMaxOpenIteratorsPerDatabase, &leveldb); + std::tie(ldb_state, status, std::ignore) = + OpenLevelDB(temp_directory.GetPath()); + EXPECT_TRUE(status.ok()); + leveldb = std::make_unique<LevelDBDatabase>( + std::move(ldb_state), nullptr, kDefaultMaxOpenIteratorsPerDatabase); EXPECT_TRUE(leveldb); bool found = false; status = leveldb->Get(key, &got_value, &found); @@ -70,19 +108,21 @@ EXPECT_TRUE( leveldb_chrome::CorruptClosedDBForTesting(temp_directory.GetPath())); - status = LevelDBDatabase::Open(temp_directory.GetPath(), &comparator, - kDefaultMaxOpenIteratorsPerDatabase, &leveldb); - EXPECT_FALSE(leveldb); + std::tie(ldb_state, status, std::ignore) = + OpenLevelDB(temp_directory.GetPath()); EXPECT_FALSE(status.ok()); EXPECT_TRUE(status.IsCorruption()); - status = LevelDBDatabase::Destroy(temp_directory.GetPath()); + status = indexed_db::GetDefaultLevelDBFactory()->DestroyLevelDB( + temp_directory.GetPath()); EXPECT_TRUE(status.ok()); - status = LevelDBDatabase::Open(temp_directory.GetPath(), &comparator, - kDefaultMaxOpenIteratorsPerDatabase, &leveldb); + std::tie(ldb_state, status, std::ignore) = + OpenLevelDB(temp_directory.GetPath()); EXPECT_TRUE(status.ok()); - EXPECT_TRUE(leveldb); + leveldb = std::make_unique<LevelDBDatabase>( + std::move(ldb_state), nullptr, kDefaultMaxOpenIteratorsPerDatabase); + ASSERT_TRUE(leveldb); status = leveldb->Get(key, &got_value, &found); EXPECT_TRUE(status.ok()); EXPECT_FALSE(found); @@ -120,14 +160,20 @@ auto test_clock = std::make_unique<base::SimpleTestClock>(); base::SimpleTestClock* clock_ptr = test_clock.get(); clock_ptr->Advance(base::TimeDelta::FromHours(2)); - std::unique_ptr<LevelDBDatabase> leveldb = - LevelDBDatabase::OpenInMemory(&comparator); + + leveldb::Status status; + scoped_refptr<LevelDBState> ldb_state; + std::tie(ldb_state, status, std::ignore) = OpenLevelDB(base::FilePath()); + EXPECT_TRUE(status.ok()); + + std::unique_ptr<LevelDBDatabase> leveldb = std::make_unique<LevelDBDatabase>( + std::move(ldb_state), nullptr, kDefaultMaxOpenIteratorsPerDatabase); ASSERT_TRUE(leveldb); leveldb->SetClockForTesting(std::move(test_clock)); // Calling |Put| sets time modified. put_value = value; base::Time now_time = clock_ptr->Now(); - leveldb::Status status = leveldb->Put(key, &put_value); + status = leveldb->Put(key, &put_value); EXPECT_TRUE(status.ok()); EXPECT_EQ(now_time, leveldb->LastModified());
diff --git a/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc b/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc deleted file mode 100644 index 61ff10b..0000000 --- a/content/browser/indexed_db/leveldb/mock_leveldb_factory.cc +++ /dev/null
@@ -1,14 +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/browser/indexed_db/leveldb/mock_leveldb_factory.h" - -namespace content { - -MockLevelDBFactory::MockLevelDBFactory() { -} - -MockLevelDBFactory::~MockLevelDBFactory() { -} - -} // namespace content
diff --git a/content/browser/indexed_db/leveldb/mock_leveldb_factory.h b/content/browser/indexed_db/leveldb/mock_leveldb_factory.h deleted file mode 100644 index b01f6e1..0000000 --- a/content/browser/indexed_db/leveldb/mock_leveldb_factory.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 CONTENT_BROWSER_INDEXED_DB_LEVELDB_MOCK_LEVELDB_FACTORY_H_ -#define CONTENT_BROWSER_INDEXED_DB_LEVELDB_MOCK_LEVELDB_FACTORY_H_ - -#include "base/files/file_path.h" -#include "content/browser/indexed_db/leveldb/leveldb_factory.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace content { - -class MockLevelDBFactory : public LevelDBFactory { - public: - MockLevelDBFactory(); - ~MockLevelDBFactory() override; - MOCK_METHOD4(OpenLevelDB, - leveldb::Status(const base::FilePath& file_name, - const LevelDBComparator* comparator, - std::unique_ptr<LevelDBDatabase>* db, - bool* is_disk_full)); - MOCK_METHOD1(DestroyLevelDB, - leveldb::Status(const base::FilePath& file_name)); -}; - -} // namespace content - -#endif // CONTENT_BROWSER_INDEXED_DB_LEVELDB_MOCK_LEVELDB_FACTORY_H_
diff --git a/content/browser/indexed_db/mock_indexed_db_factory.h b/content/browser/indexed_db/mock_indexed_db_factory.h index 53274cf..25c1d62 100644 --- a/content/browser/indexed_db/mock_indexed_db_factory.h +++ b/content/browser/indexed_db/mock_indexed_db_factory.h
@@ -103,22 +103,13 @@ protected: ~MockIndexedDBFactory() override; - MOCK_METHOD5(OpenBackingStore, - scoped_refptr<IndexedDBBackingStore>( - const url::Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - leveldb::Status* s)); - - MOCK_METHOD6(OpenBackingStoreHelper, - scoped_refptr<IndexedDBBackingStore>( - const url::Origin& origin, - const base::FilePath& data_directory, - IndexedDBDataLossInfo* data_loss_info, - bool* disk_full, - bool first_time, - leveldb::Status* s)); + MOCK_METHOD2( + OpenBackingStore, + std::tuple<scoped_refptr<IndexedDBBackingStore>, + leveldb::Status, + IndexedDBDataLossInfo, + bool /* disk_full */>(const url::Origin& origin, + const base::FilePath& data_directory)); private: DISALLOW_COPY_AND_ASSIGN(MockIndexedDBFactory);
diff --git a/content/browser/indexed_db/scopes/leveldb_state.cc b/content/browser/indexed_db/scopes/leveldb_state.cc new file mode 100644 index 0000000..868ff96 --- /dev/null +++ b/content/browser/indexed_db/scopes/leveldb_state.cc
@@ -0,0 +1,58 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <content/browser/indexed_db/scopes/leveldb_state.h> +#include "base/memory/ptr_util.h" +#include "base/metrics/histogram_macros.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" + +namespace content { + +// static +scoped_refptr<LevelDBState> LevelDBState::CreateForDiskDB( + const leveldb::Comparator* comparator, + const LevelDBComparator* idb_comparator, + std::unique_ptr<leveldb::DB> database, + base::FilePath database_path) { + return base::WrapRefCounted(new LevelDBState( + nullptr, comparator, idb_comparator, std::move(database), + std::move(database_path), database_path.BaseName().AsUTF8Unsafe())); +} + +// static +scoped_refptr<LevelDBState> LevelDBState::CreateForInMemoryDB( + std::unique_ptr<leveldb::Env> in_memory_env, + const leveldb::Comparator* comparator, + const LevelDBComparator* idb_comparator, + std::unique_ptr<leveldb::DB> in_memory_database, + std::string name_for_tracing) { + return base::WrapRefCounted( + new LevelDBState(std::move(in_memory_env), comparator, idb_comparator, + std::move(in_memory_database), base::FilePath(), + std::move(name_for_tracing))); +} + +LevelDBState::LevelDBState(std::unique_ptr<leveldb::Env> optional_in_memory_env, + const leveldb::Comparator* comparator, + const LevelDBComparator* idb_comparator, + std::unique_ptr<leveldb::DB> database, + base::FilePath database_path, + std::string name_for_tracing) + : in_memory_env_(std::move(optional_in_memory_env)), + comparator_(comparator), + idb_comparator_(idb_comparator), + db_(std::move(database)), + database_path_(std::move(database_path)), + name_for_tracing_(std::move(name_for_tracing)) {} + +LevelDBState::~LevelDBState() { + if (!db_) + return; + base::TimeTicks begin_time = base::TimeTicks::Now(); + const_cast<std::unique_ptr<leveldb::DB>*>(&db_)->reset(); + UMA_HISTOGRAM_MEDIUM_TIMES("WebCore.IndexedDB.LevelDB.CloseTime", + base::TimeTicks::Now() - begin_time); +} + +} // namespace content
diff --git a/content/browser/indexed_db/scopes/leveldb_state.h b/content/browser/indexed_db/scopes/leveldb_state.h new file mode 100644 index 0000000..e3dcf5c3 --- /dev/null +++ b/content/browser/indexed_db/scopes/leveldb_state.h
@@ -0,0 +1,70 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_INDEXED_DB_SCOPES_LEVELDB_STATE_H_ +#define CONTENT_BROWSER_INDEXED_DB_SCOPES_LEVELDB_STATE_H_ + +#include "base/memory/ref_counted.h" + +#include <memory> + +#include "base/files/file_path.h" +#include "content/browser/indexed_db/leveldb/leveldb_comparator.h" +#include "content/common/content_export.h" +#include "third_party/leveldatabase/src/include/leveldb/comparator.h" +#include "third_party/leveldatabase/src/include/leveldb/db.h" +#include "third_party/leveldatabase/src/include/leveldb/filter_policy.h" + +namespace content { + +// Encapsulates a leveldb database and comparator, allowing them to be used +// safely across thread boundaries. +class CONTENT_EXPORT LevelDBState + : public base::RefCountedThreadSafe<LevelDBState> { + public: + static scoped_refptr<LevelDBState> CreateForDiskDB( + const leveldb::Comparator* comparator, + const LevelDBComparator* idb_comparator, + std::unique_ptr<leveldb::DB> database, + base::FilePath database_path); + + static scoped_refptr<LevelDBState> CreateForInMemoryDB( + std::unique_ptr<leveldb::Env> in_memory_env, + const leveldb::Comparator* comparator, + const LevelDBComparator* idb_comparator, + std::unique_ptr<leveldb::DB> in_memory_database, + std::string name_for_tracing); + + const leveldb::Comparator* comparator() const { return comparator_; } + const LevelDBComparator* idb_comparator() const { return idb_comparator_; } + leveldb::DB* db() const { return db_.get(); } + const std::string& name_for_tracing() const { return name_for_tracing_; } + + // Null for on-disk databases. + leveldb::Env* in_memory_env() const { return in_memory_env_.get(); } + // Empty for in-memory databases. + const base::FilePath& database_path() const { return database_path_; } + + private: + friend class base::RefCountedThreadSafe<LevelDBState>; + + LevelDBState(std::unique_ptr<leveldb::Env> optional_in_memory_env, + const leveldb::Comparator* comparator, + const LevelDBComparator* idb_comparator, + std::unique_ptr<leveldb::DB> database, + base::FilePath database_path, + std::string name_for_tracing); + ~LevelDBState(); + + const std::unique_ptr<leveldb::Env> in_memory_env_; + const leveldb::Comparator* comparator_; + const LevelDBComparator* idb_comparator_; + const std::unique_ptr<leveldb::DB> db_; + const base::FilePath database_path_; + const std::string name_for_tracing_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_INDEXED_DB_SCOPES_LEVELDB_STATE_H_
diff --git a/content/browser/loader/cross_site_document_resource_handler.cc b/content/browser/loader/cross_site_document_resource_handler.cc index 8f434fc..7d5a3367 100644 --- a/content/browser/loader/cross_site_document_resource_handler.cc +++ b/content/browser/loader/cross_site_document_resource_handler.cc
@@ -593,13 +593,12 @@ // (i.e. CanAccessDataForOrigin would only plug one hole in the // non-NetworkService world) // 2) we hope that NetworkService will ship soon. - constexpr auto kInitiatorLockCompatibility = - network::InitiatorLockCompatibility::kCompatibleLock; + base::Optional<url::Origin> kInitiatorLock = base::nullopt; // Delegate most decisions to CrossOriginReadBlocking::ResponseAnalyzer. analyzer_ = std::make_unique<network::CrossOriginReadBlocking::ResponseAnalyzer>( - *request(), response, kInitiatorLockCompatibility); + *request(), response, kInitiatorLock); if (analyzer_->ShouldAllow()) return false;
diff --git a/content/browser/net/net_command_line_flags_browsertest.cc b/content/browser/net/net_command_line_flags_browsertest.cc new file mode 100644 index 0000000..e47cbbf0 --- /dev/null +++ b/content/browser/net/net_command_line_flags_browsertest.cc
@@ -0,0 +1,52 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/public/browser/browser_context.h" +#include "content/public/browser/storage_partition.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/content_browser_test.h" +#include "content/shell/browser/shell.h" +#include "services/network/public/cpp/network_switches.h" + +namespace content { + +class CommandLineFlagsBrowserTest : public ContentBrowserTest { + protected: + network::mojom::NetworkContext* network_context() { + return content::BrowserContext::GetDefaultStoragePartition( + shell()->web_contents()->GetBrowserContext()) + ->GetNetworkContext(); + } +}; + +// Tests that when no special command line flags are passed, requests to port 79 +// (finger) fail with ERR_UNSAFE_PORT. +IN_PROC_BROWSER_TEST_F(CommandLineFlagsBrowserTest, Port79DefaultBlocked) { + EXPECT_EQ(net::ERR_UNSAFE_PORT, + content::LoadBasicRequest(network_context(), + GURL("http://127.0.0.1:79"), 0, 0, 0)); +} + +class ExplicitlyAllowPort79BrowserTest : public CommandLineFlagsBrowserTest { + public: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII(network::switches::kExplicitlyAllowedPorts, + "79"); + } +}; + +// Tests that when run with the flag --explicitly-allowed-ports=79, requests to +// port 79 (finger) are permitted. +// +// The request may succeed or fail depending on the platform and what services +// are running, so the test just verifies the reason for failure is not +// ERR_UNSAFE_PORT. +IN_PROC_BROWSER_TEST_F(ExplicitlyAllowPort79BrowserTest, Load) { + EXPECT_NE(net::ERR_UNSAFE_PORT, + content::LoadBasicRequest(network_context(), + GURL("http://127.0.0.1:79"), 0, 0, 0)); +} + +} // 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 aac3f05..b8a0e79 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2982,6 +2982,7 @@ // with any associated values) if present in the browser command line. static const char* const kSwitchNames[] = { network::switches::kNoReferrers, + network::switches::kExplicitlyAllowedPorts, service_manager::switches::kDisableInProcessStackTraces, service_manager::switches::kDisableSeccompFilterSandbox, service_manager::switches::kNoSandbox, @@ -3064,7 +3065,6 @@ switches::kEnableWebGLDraftExtensions, switches::kEnableWebGLImageChromium, switches::kEnableWebVR, - switches::kExplicitlyAllowedPorts, switches::kFileUrlPathAlias, switches::kForceDisplayColorProfile, switches::kForceDeviceScaleFactor,
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc index b775221..efe239e 100644 --- a/content/browser/storage_partition_impl.cc +++ b/content/browser/storage_partition_impl.cc
@@ -34,6 +34,7 @@ #include "content/browser/cookie_store/cookie_store_context.h" #include "content/browser/fileapi/browser_file_system_helper.h" #include "content/browser/gpu/shader_cache_factory.h" +#include "content/browser/indexed_db/leveldb/leveldb_env.h" #include "content/browser/loader/prefetch_url_loader_service.h" #include "content/browser/notifications/platform_notification_context_impl.h" #include "content/common/dom_storage/dom_storage_types.h" @@ -643,7 +644,8 @@ base::FilePath path = in_memory ? base::FilePath() : partition_path; partition->indexed_db_context_ = new IndexedDBContextImpl( - path, context->GetSpecialStoragePolicy(), quota_manager_proxy); + path, context->GetSpecialStoragePolicy(), quota_manager_proxy, + indexed_db::GetDefaultLevelDBFactory()); partition->cache_storage_context_ = new CacheStorageContextImpl(context); partition->cache_storage_context_->Init(path, quota_manager_proxy);
diff --git a/content/browser/utility_process_host.cc b/content/browser/utility_process_host.cc index 074f2906..5e1c913 100644 --- a/content/browser/utility_process_host.cc +++ b/content/browser/utility_process_host.cc
@@ -352,6 +352,7 @@ network::switches::kIgnoreUrlFetcherCertRequests, network::switches::kLogNetLog, network::switches::kNoReferrers, + network::switches::kExplicitlyAllowedPorts, service_manager::switches::kNoSandbox, #if defined(OS_MACOSX) service_manager::switches::kEnableSandboxLogging,
diff --git a/content/browser/web_contents/web_contents_view_cocoa.mm b/content/browser/web_contents/web_contents_view_cocoa.mm index 5cb0953..53bd394 100644 --- a/content/browser/web_contents/web_contents_view_cocoa.mm +++ b/content/browser/web_contents/web_contents_view_cocoa.mm
@@ -14,10 +14,8 @@ #include "content/public/browser/web_contents_view_delegate.h" #import "third_party/mozilla/NSPasteboard+Utils.h" #include "ui/base/clipboard/custom_data_helper.h" -#include "ui/base/cocoa/cocoa_base_utils.h" #include "ui/base/dragdrop/cocoa_dnd_util.h" -using content::DraggingInfo; using content::DropData; using content::WebContentsImpl; using content::WebContentsViewMac; @@ -61,33 +59,6 @@ [super dealloc]; } -- (void)populateDraggingInfo:(DraggingInfo*)info - fromNSDraggingInfo:(id<NSDraggingInfo>)nsInfo { - NSPoint windowPoint = [nsInfo draggingLocation]; - - NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil]; - NSRect viewFrame = [self frame]; - info->location_in_view = - gfx::PointF(viewPoint.x, viewFrame.size.height - viewPoint.y); - - NSPoint screenPoint = - ui::ConvertPointFromWindowToScreen([self window], windowPoint); - NSScreen* screen = [[self window] screen]; - NSRect screenFrame = [screen frame]; - info->location_in_screen = - gfx::PointF(screenPoint.x, screenFrame.size.height - screenPoint.y); - - info->location_in_view = gfx::PointF(viewPoint.x, viewPoint.y); - info->location_in_screen = gfx::PointF(screenPoint.x, screenPoint.y); - NSPasteboard* pboard = [nsInfo draggingPasteboard]; - if ([pboard containsURLDataConvertingTextToURL:YES]) { - GURL url; - ui::PopulateURLAndTitleFromPasteboard(&url, NULL, pboard, YES); - info->url.emplace(url); - } - info->operation_mask = [nsInfo draggingSourceOperationMask]; -} - - (BOOL)allowsVibrancy { // Returning YES will allow rendering this view with vibrancy effect if it is // incorporated into a view hierarchy that uses vibrancy, it will have no @@ -214,10 +185,7 @@ content::PopulateDropDataFromPasteboard(&dropData, [sender draggingPasteboard]); [dragDest_ setDropData:dropData]; - - DraggingInfo draggingInfo; - [self populateDraggingInfo:&draggingInfo fromNSDraggingInfo:sender]; - return [dragDest_ draggingEntered:draggingInfo]; + return [dragDest_ draggingEntered:sender view:self]; } - (void)draggingExited:(id<NSDraggingInfo>)sender { @@ -225,15 +193,11 @@ } - (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)sender { - DraggingInfo draggingInfo; - [self populateDraggingInfo:&draggingInfo fromNSDraggingInfo:sender]; - return [dragDest_ draggingUpdated:draggingInfo]; + return [dragDest_ draggingUpdated:sender view:self]; } - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender { - DraggingInfo draggingInfo; - [self populateDraggingInfo:&draggingInfo fromNSDraggingInfo:sender]; - return [dragDest_ performDragOperation:draggingInfo]; + return [dragDest_ performDragOperation:sender view:self]; } - (void)cancelDeferredClose {
diff --git a/content/browser/web_contents/web_drag_dest_mac.h b/content/browser/web_contents/web_drag_dest_mac.h index 0f51b9f..990cd2cd5 100644 --- a/content/browser/web_contents/web_drag_dest_mac.h +++ b/content/browser/web_contents/web_drag_dest_mac.h
@@ -33,27 +33,6 @@ void CONTENT_EXPORT PopulateDropDataFromPasteboard(content::DropData* data, NSPasteboard* pboard); -// The data extracted from an NSDraggingInfo needed by draggingEntered, -// draggingUpdated, and performDragOperation. -// TODO(https://crbug.com/898608): Change this to be a mojo structure. -struct CONTENT_EXPORT DraggingInfo { - DraggingInfo(); - ~DraggingInfo(); - - // The dragging location in the NSView, with the origin in the upper-left. - gfx::PointF location_in_view; - - // The dragging location in the NSScreen, with the origin in the upper-left. - gfx::PointF location_in_screen; - - // The URL data from the drag, if any. Note that this is redundant in that it - // is already present in DropData. It is here because it is used by methods - // that don't use DropData. - base::Optional<GURL> url; - - // The operation mask. - uint32_t operation_mask; -}; } // A class that handles tracking and event processing for a drag and drop @@ -116,15 +95,17 @@ // Messages to send during the tracking of a drag, ususally upon receiving // calls from the view system. Communicates the drag messages to WebCore. - (void)setDropData:(const content::DropData&)dropData; -- (NSDragOperation)draggingEntered:(const content::DraggingInfo&)info; +- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info + view:(NSView*)view; - (void)draggingExited; -- (NSDragOperation)draggingUpdated:(const content::DraggingInfo&)info; -- (BOOL)performDragOperation:(const content::DraggingInfo&)info; +- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info + view:(NSView*)view; +- (BOOL)performDragOperation:(id<NSDraggingInfo>)info view:(NSView*)view; // Helper to call WebWidgetHostInputEventRouter::GetRenderWidgetHostAtPoint(). - (content::RenderWidgetHostImpl*) - GetRenderWidgetHostAtPoint:(const gfx::PointF&)viewPoint - transformedPt:(gfx::PointF*)transformedPt; +GetRenderWidgetHostAtPoint:(const NSPoint&)viewPoint + transformedPt:(gfx::PointF*)transformedPt; // Sets |dragStartProcessID_| and |dragStartViewID_|. - (void)setDragStartTrackersForProcess:(int)processID;
diff --git a/content/browser/web_contents/web_drag_dest_mac.mm b/content/browser/web_contents/web_drag_dest_mac.mm index e8ae8e1f..e9d6a913 100644 --- a/content/browser/web_contents/web_drag_dest_mac.mm +++ b/content/browser/web_contents/web_drag_dest_mac.mm
@@ -26,7 +26,6 @@ #include "ui/gfx/geometry/point.h" using blink::WebDragOperationsMask; -using content::DraggingInfo; using content::DropData; using content::OpenURLParams; using content::Referrer; @@ -138,11 +137,17 @@ dropDataUnfiltered_ = std::make_unique<DropData>(dropData); } -- (NSDragOperation)draggingEntered:(const DraggingInfo&)info { +- (NSDragOperation)draggingEntered:(id<NSDraggingInfo>)info + view:(NSView*)view { // Save off the RVH so we can tell if it changes during a drag. If it does, // we need to send a new enter message in draggingUpdated:. currentRVH_ = webContents_->GetRenderViewHost(); + // Create the appropriate mouse locations for WebCore. The draggingLocation + // is in window coordinates. Both need to be flipped. + NSPoint windowPoint = [info draggingLocation]; + NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view]; + NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view]; gfx::PointF transformedPt; if (!webContents_->GetRenderWidgetHostView()) { // TODO(ekaramad, paulmeyer): Find a better way than toggling |canceled_|. @@ -153,8 +158,7 @@ } content::RenderWidgetHostImpl* targetRWH = - [self GetRenderWidgetHostAtPoint:info.location_in_view - transformedPt:&transformedPt]; + [self GetRenderWidgetHostAtPoint:viewPoint transformedPt:&transformedPt]; if (![self isValidDragTarget:targetRWH]) return NSDragOperationNone; @@ -166,7 +170,7 @@ currentRWHForDrag_ = targetRWH->GetWeakPtr(); currentRWHForDrag_->FilterDropData(dropData.get()); - NSDragOperation mask = info.operation_mask; + NSDragOperation mask = [info draggingSourceOperationMask]; // Give the delegate an opportunity to cancel the drag. canceled_ = !webContents_->GetDelegate()->CanDragEnter( @@ -177,7 +181,7 @@ return NSDragOperationNone; if ([self onlyAllowsNavigation]) { - if (info.url) + if ([[info draggingPasteboard] containsURLDataConvertingTextToURL:YES]) return NSDragOperationCopy; return NSDragOperationNone; } @@ -190,7 +194,8 @@ dropDataFiltered_.swap(dropData); currentRWHForDrag_->DragTargetDragEnter( - *dropDataFiltered_, transformedPt, info.location_in_screen, + *dropDataFiltered_, transformedPt, + gfx::PointF(screenPoint.x, screenPoint.y), static_cast<WebDragOperationsMask>(mask), GetModifierFlags()); // We won't know the true operation (whether the drag is allowed) until we @@ -221,17 +226,21 @@ dropDataFiltered_.reset(); } -- (NSDragOperation)draggingUpdated:(const DraggingInfo&)info { +- (NSDragOperation)draggingUpdated:(id<NSDraggingInfo>)info view:(NSView*)view { if (canceled_) { // TODO(ekaramad,paulmeyer): We probably shouldn't be checking for // |canceled_| twice in this method. return NSDragOperationNone; } + // Create the appropriate mouse locations for WebCore. The draggingLocation + // is in window coordinates. Both need to be flipped. + NSPoint windowPoint = [info draggingLocation]; + NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view]; + NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view]; gfx::PointF transformedPt; content::RenderWidgetHostImpl* targetRWH = - [self GetRenderWidgetHostAtPoint:info.location_in_view - transformedPt:&transformedPt]; + [self GetRenderWidgetHostAtPoint:viewPoint transformedPt:&transformedPt]; if (![self isValidDragTarget:targetRWH]) return NSDragOperationNone; @@ -240,8 +249,9 @@ // per drag, even without the drag ever leaving the window. if (targetRWH != currentRWHForDrag_.get()) { if (currentRWHForDrag_) { - gfx::PointF transformedLeavePoint = info.location_in_view; - gfx::PointF transformedScreenPoint = info.location_in_screen; + gfx::PointF transformedLeavePoint = gfx::PointF(viewPoint.x, viewPoint.y); + gfx::PointF transformedScreenPoint = + gfx::PointF(screenPoint.x, screenPoint.y); content::RenderWidgetHostViewBase* rootView = static_cast<content::RenderWidgetHostViewBase*>( webContents_->GetRenderWidgetHostView()); @@ -255,22 +265,22 @@ currentRWHForDrag_->DragTargetDragLeave(transformedLeavePoint, transformedScreenPoint); } - [self draggingEntered:info]; + [self draggingEntered:info view:view]; } if (canceled_) return NSDragOperationNone; if ([self onlyAllowsNavigation]) { - if (info.url) + if ([[info draggingPasteboard] containsURLDataConvertingTextToURL:YES]) return NSDragOperationCopy; return NSDragOperationNone; } - NSDragOperation mask = info.operation_mask; - targetRWH->DragTargetDragOver(transformedPt, info.location_in_screen, - static_cast<WebDragOperationsMask>(mask), - GetModifierFlags()); + NSDragOperation mask = [info draggingSourceOperationMask]; + targetRWH->DragTargetDragOver( + transformedPt, gfx::PointF(screenPoint.x, screenPoint.y), + static_cast<WebDragOperationsMask>(mask), GetModifierFlags()); if (delegate_) delegate_->OnDragOver(); @@ -278,28 +288,36 @@ return currentOperation_; } -- (BOOL)performDragOperation:(const DraggingInfo&)info { +- (BOOL)performDragOperation:(id<NSDraggingInfo>)info + view:(NSView*)view { + // Create the appropriate mouse locations for WebCore. The draggingLocation + // is in window coordinates. Both need to be flipped. + NSPoint windowPoint = [info draggingLocation]; + NSPoint viewPoint = [self flipWindowPointToView:windowPoint view:view]; + NSPoint screenPoint = [self flipWindowPointToScreen:windowPoint view:view]; gfx::PointF transformedPt; content::RenderWidgetHostImpl* targetRWH = - [self GetRenderWidgetHostAtPoint:info.location_in_view - transformedPt:&transformedPt]; + [self GetRenderWidgetHostAtPoint:viewPoint transformedPt:&transformedPt]; if (![self isValidDragTarget:targetRWH]) return NO; if (targetRWH != currentRWHForDrag_.get()) { if (currentRWHForDrag_) - currentRWHForDrag_->DragTargetDragLeave(transformedPt, - info.location_in_screen); - [self draggingEntered:info]; + currentRWHForDrag_->DragTargetDragLeave( + transformedPt, gfx::PointF(screenPoint.x, screenPoint.y)); + [self draggingEntered:info view:view]; } // Check if we only allow navigation and navigate to a url on the pasteboard. if ([self onlyAllowsNavigation]) { - if (info.url) { - webContents_->OpenURL(OpenURLParams( - *info.url, Referrer(), WindowOpenDisposition::CURRENT_TAB, - ui::PAGE_TRANSITION_AUTO_BOOKMARK, false)); + NSPasteboard* pboard = [info draggingPasteboard]; + if ([pboard containsURLDataConvertingTextToURL:YES]) { + GURL url; + ui::PopulateURLAndTitleFromPasteboard(&url, NULL, pboard, YES); + webContents_->OpenURL( + OpenURLParams(url, Referrer(), WindowOpenDisposition::CURRENT_TAB, + ui::PAGE_TRANSITION_AUTO_BOOKMARK, false)); return YES; } else { return NO; @@ -312,7 +330,8 @@ currentRVH_ = NULL; targetRWH->DragTargetDrop(*dropDataFiltered_, transformedPt, - info.location_in_screen, GetModifierFlags()); + gfx::PointF(screenPoint.x, screenPoint.y), + GetModifierFlags()); dropDataUnfiltered_.reset(); dropDataFiltered_.reset(); @@ -321,11 +340,11 @@ } - (content::RenderWidgetHostImpl*) - GetRenderWidgetHostAtPoint:(const gfx::PointF&)viewPoint - transformedPt:(gfx::PointF*)transformedPt { +GetRenderWidgetHostAtPoint:(const NSPoint&)viewPoint + transformedPt:(gfx::PointF*)transformedPt { return webContents_->GetInputEventRouter()->GetRenderWidgetHostAtPoint( - webContents_->GetRenderViewHost()->GetWidget()->GetView(), viewPoint, - transformedPt); + webContents_->GetRenderViewHost()->GetWidget()->GetView(), + gfx::PointF(viewPoint.x, viewPoint.y), transformedPt); } - (void)setDragStartTrackersForProcess:(int)processID { @@ -406,7 +425,4 @@ } } -DraggingInfo::DraggingInfo() = default; -DraggingInfo::~DraggingInfo() = default; - } // namespace content
diff --git a/content/browser/web_contents/web_drag_dest_mac_unittest.mm b/content/browser/web_contents/web_drag_dest_mac_unittest.mm index b837cbd..3ecdcc8 100644 --- a/content/browser/web_contents/web_drag_dest_mac_unittest.mm +++ b/content/browser/web_contents/web_drag_dest_mac_unittest.mm
@@ -66,6 +66,24 @@ EXPECT_TRUE(drag_dest_); } +// Test flipping of coordinates given a point in window coordinates. +TEST_F(WebDragDestTest, Flip) { + NSPoint windowPoint = NSZeroPoint; + base::scoped_nsobject<NSWindow> window([[CocoaTestHelperWindow alloc] init]); + NSPoint viewPoint = + [drag_dest_ flipWindowPointToView:windowPoint + view:[window contentView]]; + NSPoint screenPoint = + [drag_dest_ flipWindowPointToScreen:windowPoint + view:[window contentView]]; + EXPECT_EQ(0, viewPoint.x); + EXPECT_EQ(600, viewPoint.y); + EXPECT_EQ(0, screenPoint.x); + // We can't put a value on the screen size since everyone will have a + // different one. + EXPECT_NE(0, screenPoint.y); +} + TEST_F(WebDragDestTest, URL) { NSString* url = nil; NSString* title = nil;
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc index 1c96f168..0b9d501 100644 --- a/content/gpu/gpu_main.cc +++ b/content/gpu/gpu_main.cc
@@ -64,6 +64,7 @@ #endif #if defined(OS_WIN) +#include "base/trace_event/trace_event_etw_export_win.h" #include "base/win/scoped_com_initializer.h" #include "base/win/windows_version.h" #include "media/gpu/windows/dxva_video_decode_accelerator_win.h" @@ -211,6 +212,11 @@ if (gpu_preferences.gpu_startup_dialog) WaitForDebugger("Gpu"); +#if defined(OS_WIN) + if (gpu_preferences.enable_trace_export_events_to_etw) + base::trace_event::TraceEventETWExport::EnableETWExport(); +#endif + base::Time start_time = base::Time::Now(); #if defined(OS_WIN)
diff --git a/content/public/browser/gpu_utils.cc b/content/public/browser/gpu_utils.cc index d6162ed..267af69 100644 --- a/content/public/browser/gpu_utils.cc +++ b/content/public/browser/gpu_utils.cc
@@ -95,6 +95,10 @@ command_line->HasSwitch(switches::kDisableSoftwareRasterizer); gpu_preferences.log_gpu_control_list_decisions = command_line->HasSwitch(switches::kLogGpuControlListDecisions); +#if defined(OS_WIN) + gpu_preferences.enable_trace_export_events_to_etw = + command_line->HasSwitch(switches::kTraceExportEventsToETW); +#endif GetUintFromSwitch(command_line, switches::kMaxActiveWebGLContexts, &gpu_preferences.max_active_webgl_contexts); gpu_preferences.gpu_startup_dialog =
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc index eeb540b..512d0bb9 100644 --- a/content/public/common/content_switches.cc +++ b/content/public/common/content_switches.cc
@@ -462,10 +462,6 @@ // Enable rasterizer that writes directly to GPU memory associated with tiles. const char kEnableZeroCopy[] = "enable-zero-copy"; -// Explicitly allows additional ports using a comma-separated list of port -// numbers. -const char kExplicitlyAllowedPorts[] = "explicitly-allowed-ports"; - // Handle to the shared memory segment containing field trial state that is to // be shared between processes. The argument to this switch is the handle id // (pointer on Windows) as a string, followed by a comma, then the size of the
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h index 2a08de6a..f420773 100644 --- a/content/public/common/content_switches.h +++ b/content/public/common/content_switches.h
@@ -146,7 +146,6 @@ CONTENT_EXPORT extern const char kEnableWebGLImageChromium[]; CONTENT_EXPORT extern const char kEnableWebVR[]; CONTENT_EXPORT extern const char kEnableZeroCopy[]; -CONTENT_EXPORT extern const char kExplicitlyAllowedPorts[]; CONTENT_EXPORT extern const char kFieldTrialHandle[]; CONTENT_EXPORT extern const char kFileUrlPathAlias[]; CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
diff --git a/content/renderer/compositor/layer_tree_view.cc b/content/renderer/compositor/layer_tree_view.cc index f39f7cb..cbe23e1 100644 --- a/content/renderer/compositor/layer_tree_view.cc +++ b/content/renderer/compositor/layer_tree_view.cc
@@ -428,22 +428,6 @@ return false; } -void LayerTreeView::LayoutAndPaintAsync(base::OnceClosure callback) { - DCHECK(layout_and_paint_async_callback_.is_null()); - layout_and_paint_async_callback_ = std::move(callback); - - if (CompositeIsSynchronous()) { - // The LayoutAndPaintAsyncCallback is invoked in WillCommit, which is - // dispatched after layout and paint for all compositing modes. - const bool raster = false; - layer_tree_host_->GetTaskRunnerProvider()->MainThreadTaskRunner()->PostTask( - FROM_HERE, base::BindOnce(&LayerTreeView::SynchronouslyComposite, - weak_factory_.GetWeakPtr(), raster, nullptr)); - } else { - layer_tree_host_->SetNeedsCommit(); - } -} - void LayerTreeView::SetLayerTreeFrameSink( std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink) { if (!layer_tree_frame_sink) { @@ -453,14 +437,8 @@ layer_tree_host_->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink)); } -void LayerTreeView::InvokeLayoutAndPaintCallback() { - if (!layout_and_paint_async_callback_.is_null()) - std::move(layout_and_paint_async_callback_).Run(); -} - void LayerTreeView::CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) { - DCHECK(layout_and_paint_async_callback_.is_null()); scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner = layer_tree_host_->GetTaskRunnerProvider()->MainThreadTaskRunner(); std::unique_ptr<viz::CopyOutputRequest> request = @@ -712,9 +690,7 @@ weak_factory_.GetWeakPtr())); } -void LayerTreeView::WillCommit() { - InvokeLayoutAndPaintCallback(); -} +void LayerTreeView::WillCommit() {} void LayerTreeView::DidCommit() { delegate_->DidCommitCompositorFrame();
diff --git a/content/renderer/compositor/layer_tree_view.h b/content/renderer/compositor/layer_tree_view.h index 7590a49..3e01903 100644 --- a/content/renderer/compositor/layer_tree_view.h +++ b/content/renderer/compositor/layer_tree_view.h
@@ -145,7 +145,6 @@ double duration_sec) override; bool HasPendingPageScaleAnimation() const override; void HeuristicsForGpuRasterizationUpdated(bool matches_heuristics) override; - void LayoutAndPaintAsync(base::OnceClosure callback) override; void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) override; // Synchronously performs the complete set of document lifecycle phases, @@ -242,7 +241,6 @@ private: void SetLayerTreeFrameSink( std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink); - void InvokeLayoutAndPaintCallback(); bool CompositeIsSynchronous() const; void SynchronouslyComposite(bool raster, std::unique_ptr<cc::SwapPromise> swap_promise); @@ -259,7 +257,6 @@ bool layer_tree_frame_sink_request_failed_while_invisible_ = false; bool in_synchronous_compositor_update_ = false; - base::OnceClosure layout_and_paint_async_callback_; viz::FrameSinkId frame_sink_id_; base::circular_deque<
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 2e17bf6..44df5d5 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -138,6 +138,7 @@ #include "net/base/url_util.h" #include "ppapi/buildflags/buildflags.h" #include "services/metrics/public/cpp/mojo_ukm_recorder.h" +#include "services/network/public/cpp/network_switches.h" #include "services/service_manager/public/cpp/connector.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "services/ws/public/cpp/gpu/context_provider_command_buffer.h" @@ -1233,9 +1234,9 @@ SkGraphics::SetImageGeneratorFromEncodedDataFactory( blink::WebImageGenerator::CreateAsSkImageGenerator); - if (command_line.HasSwitch(switches::kExplicitlyAllowedPorts)) { - std::string allowed_ports = - command_line.GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); + if (command_line.HasSwitch(network::switches::kExplicitlyAllowedPorts)) { + std::string allowed_ports = command_line.GetSwitchValueASCII( + network::switches::kExplicitlyAllowedPorts); net::SetExplicitlyAllowedPorts(allowed_ports); } }
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc index 444bbe5..f1441e3 100644 --- a/content/shell/renderer/web_test/blink_test_runner.cc +++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -48,7 +48,6 @@ #include "content/shell/renderer/web_test/web_test_render_thread_observer.h" #include "content/shell/test_runner/app_banner_service.h" #include "content/shell/test_runner/gamepad_controller.h" -#include "content/shell/test_runner/layout_and_paint_async_then.h" #include "content/shell/test_runner/pixel_dump.h" #include "content/shell/test_runner/web_test_interfaces.h" #include "content/shell/test_runner/web_test_runner.h"
diff --git a/content/shell/test_runner/BUILD.gn b/content/shell/test_runner/BUILD.gn index f576a6ba..f3680117 100644 --- a/content/shell/test_runner/BUILD.gn +++ b/content/shell/test_runner/BUILD.gn
@@ -31,8 +31,6 @@ "gamepad_controller.h", "gc_controller.cc", "gc_controller.h", - "layout_and_paint_async_then.cc", - "layout_and_paint_async_then.h", "layout_dump.cc", "layout_dump.h", "mock_content_settings_client.cc",
diff --git a/content/shell/test_runner/layout_and_paint_async_then.cc b/content/shell/test_runner/layout_and_paint_async_then.cc deleted file mode 100644 index 7e4dab4..0000000 --- a/content/shell/test_runner/layout_and_paint_async_then.cc +++ /dev/null
@@ -1,29 +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 "content/shell/test_runner/layout_and_paint_async_then.h" - -#include "base/barrier_closure.h" -#include "base/callback.h" -#include "base/trace_event/trace_event.h" -#include "third_party/blink/public/web/web_page_popup.h" -#include "third_party/blink/public/web/web_widget.h" - -namespace test_runner { - -void LayoutAndPaintAsyncThen(blink::WebPagePopup* popup, - blink::WebWidget* web_widget, - base::OnceClosure callback) { - TRACE_EVENT0("shell", "LayoutAndPaintAsyncThen"); - - if (popup) { - auto barrier = base::BarrierClosure(2, std::move(callback)); - web_widget->LayoutAndPaintAsync(barrier); - popup->LayoutAndPaintAsync(barrier); - } else { - web_widget->LayoutAndPaintAsync(std::move(callback)); - } -} - -} // namespace test_runner
diff --git a/content/shell/test_runner/layout_and_paint_async_then.h b/content/shell/test_runner/layout_and_paint_async_then.h deleted file mode 100644 index 798d2f1..0000000 --- a/content/shell/test_runner/layout_and_paint_async_then.h +++ /dev/null
@@ -1,27 +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_SHELL_TEST_RUNNER_LAYOUT_AND_PAINT_ASYNC_THEN_H_ -#define CONTENT_SHELL_TEST_RUNNER_LAYOUT_AND_PAINT_ASYNC_THEN_H_ - -#include "base/callback_forward.h" -#include "content/shell/test_runner/test_runner_export.h" - -namespace blink { -class WebPagePopup; -class WebWidget; -} // namespace blink - -namespace test_runner { - -// Triggers a layout and paint of WebWidget and the active popup (if any). -// Calls |callback| after the layout and paint happens for both the -// widget and the popup. -TEST_RUNNER_EXPORT void LayoutAndPaintAsyncThen(blink::WebPagePopup* popup, - blink::WebWidget* web_widget, - base::OnceClosure callback); - -} // namespace test_runner - -#endif // CONTENT_SHELL_TEST_RUNNER_LAYOUT_AND_PAINT_ASYNC_THEN_H_
diff --git a/content/shell/test_runner/test_runner.cc b/content/shell/test_runner/test_runner.cc index b9ce921..faa25a84 100644 --- a/content/shell/test_runner/test_runner.cc +++ b/content/shell/test_runner/test_runner.cc
@@ -20,7 +20,6 @@ #include "build/build_config.h" #include "cc/paint/paint_canvas.h" #include "content/shell/common/web_test/web_test_switches.h" -#include "content/shell/test_runner/layout_and_paint_async_then.h" #include "content/shell/test_runner/layout_dump.h" #include "content/shell/test_runner/mock_content_settings_client.h" #include "content/shell/test_runner/mock_screen_orientation_client.h" @@ -194,8 +193,6 @@ void UpdateAllLifecyclePhasesAndCompositeThen( v8::Local<v8::Function> callback); void SetAnimationRequiresRaster(bool do_raster); - void LayoutAndPaintAsync(); - void LayoutAndPaintAsyncThen(v8::Local<v8::Function> callback); void LogToStderr(const std::string& output); void NotImplemented(const gin::Arguments& args); void NotifyDone(); @@ -482,10 +479,6 @@ &TestRunnerBindings::UpdateAllLifecyclePhasesAndCompositeThen) .SetMethod("setAnimationRequiresRaster", &TestRunnerBindings::SetAnimationRequiresRaster) - .SetMethod("layoutAndPaintAsync", - &TestRunnerBindings::LayoutAndPaintAsync) - .SetMethod("layoutAndPaintAsyncThen", - &TestRunnerBindings::LayoutAndPaintAsyncThen) .SetMethod("logToStderr", &TestRunnerBindings::LogToStderr) .SetMethod("notifyDone", &TestRunnerBindings::NotifyDone) .SetMethod("overridePreference", &TestRunnerBindings::OverridePreference) @@ -1346,17 +1339,6 @@ runner_->SetAnimationRequiresRaster(do_raster); } -void TestRunnerBindings::LayoutAndPaintAsync() { - if (view_runner_) - view_runner_->LayoutAndPaintAsync(); -} - -void TestRunnerBindings::LayoutAndPaintAsyncThen( - v8::Local<v8::Function> callback) { - if (view_runner_) - view_runner_->LayoutAndPaintAsyncThen(callback); -} - void TestRunnerBindings::GetManifestThen(v8::Local<v8::Function> callback) { if (view_runner_) view_runner_->GetManifestThen(callback);
diff --git a/content/shell/test_runner/test_runner_for_specific_view.cc b/content/shell/test_runner/test_runner_for_specific_view.cc index e01f88e..f753784 100644 --- a/content/shell/test_runner/test_runner_for_specific_view.cc +++ b/content/shell/test_runner/test_runner_for_specific_view.cc
@@ -16,7 +16,6 @@ #include "build/build_config.h" #include "cc/paint/paint_canvas.h" #include "content/renderer/compositor/layer_tree_view.h" -#include "content/shell/test_runner/layout_and_paint_async_then.h" #include "content/shell/test_runner/layout_dump.h" #include "content/shell/test_runner/mock_content_settings_client.h" #include "content/shell/test_runner/mock_screen_orientation_client.h" @@ -217,26 +216,6 @@ v8::UniquePersistent<v8::Function>(blink::MainThreadIsolate(), callback)); } -void TestRunnerForSpecificView::LayoutAndPaintAsync() { - // TODO(lfg, lukasza): TestRunnerForSpecificView assumes that there's a single - // WebWidget for the entire view, but with out-of-process iframes there may be - // multiple WebWidgets, one for each local root. We should look into making - // this structure more generic. Also the PagePopup for an OOPIF would be - // attached to a WebView without a main frame, which should be handled. - test_runner::LayoutAndPaintAsyncThen( - web_view()->GetPagePopup(), - web_view()->MainFrame()->ToWebLocalFrame()->FrameWidget(), - base::DoNothing()); -} - -void TestRunnerForSpecificView::LayoutAndPaintAsyncThen( - v8::Local<v8::Function> callback) { - test_runner::LayoutAndPaintAsyncThen( - web_view()->GetPagePopup(), - web_view()->MainFrame()->ToWebLocalFrame()->FrameWidget(), - CreateClosureThatPostsV8Callback(callback)); -} - void TestRunnerForSpecificView::CapturePixelsAsyncThen( v8::Local<v8::Function> callback) { v8::UniquePersistent<v8::Function> persistent_callback(
diff --git a/content/shell/test_runner/test_runner_for_specific_view.h b/content/shell/test_runner/test_runner_for_specific_view.h index 3b3ddcf..64621649 100644 --- a/content/shell/test_runner/test_runner_for_specific_view.h +++ b/content/shell/test_runner/test_runner_for_specific_view.h
@@ -79,12 +79,9 @@ void UpdateAllLifecyclePhasesAndCompositeThen( v8::Local<v8::Function> callback); - void LayoutAndPaintAsync(); - void LayoutAndPaintAsyncThen(v8::Local<v8::Function> callback); - - // Similar to LayoutAndPaintAsyncThen(), but pass parameters of the captured - // snapshot (width, height, snapshot) to the callback. The snapshot is in - // uint8_t RGBA format. + // The callback will be called after the next full frame update and raster, + // with the captured snapshot as the parameters (width, height, snapshot). + // The snapshot is in uint8_t RGBA format. void CapturePixelsAsyncThen(v8::Local<v8::Function> callback); void CapturePixelsCallback(v8::UniquePersistent<v8::Function> callback, const SkBitmap& snapshot);
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 602018b..dab1cfc 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -827,6 +827,7 @@ "../browser/mojo_sandbox_browsertest.cc", "../browser/navigation_browsertest.cc", "../browser/net/accept_header_browsertest.cc", + "../browser/net/net_command_line_flags_browsertest.cc", "../browser/net_info_browsertest.cc", "../browser/network_service_browsertest.cc", "../browser/network_service_restart_browsertest.cc", @@ -1437,12 +1438,13 @@ "../browser/indexed_db/indexed_db_tombstone_sweeper_unittest.cc", "../browser/indexed_db/indexed_db_transaction_unittest.cc", "../browser/indexed_db/indexed_db_unittest.cc", + "../browser/indexed_db/leveldb/fake_leveldb_factory.cc", + "../browser/indexed_db/leveldb/fake_leveldb_factory.h", + "../browser/indexed_db/leveldb/leveldb_env_unittest.cc", "../browser/indexed_db/leveldb/leveldb_transaction_unittest.cc", "../browser/indexed_db/leveldb/leveldb_unittest.cc", "../browser/indexed_db/leveldb/mock_level_db.cc", "../browser/indexed_db/leveldb/mock_level_db.h", - "../browser/indexed_db/leveldb/mock_leveldb_factory.cc", - "../browser/indexed_db/leveldb/mock_leveldb_factory.h", "../browser/indexed_db/list_set_unittest.cc", "../browser/indexed_db/mock_indexed_db_callbacks.cc", "../browser/indexed_db/mock_indexed_db_callbacks.h",
diff --git a/content/test/data/accessibility/aria/aria-listbox-expected-blink.txt b/content/test/data/accessibility/aria/aria-listbox-expected-blink.txt index 6fee00c..dc833e6 100644 --- a/content/test/data/accessibility/aria/aria-listbox-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-listbox-expected-blink.txt
@@ -1,7 +1,7 @@ rootWebArea -++listBox -++++listBoxOption name='Item 1' setSize=2 posInSet=1 selected=false -++++listBoxOption name='Item 2' setSize=2 posInSet=2 selected=false +++listBox setSize=4 +++++listBoxOption name='Item 1' setSize=4 posInSet=1 selected=false +++++listBoxOption name='Item 2' setSize=4 posInSet=2 selected=false ++++splitter horizontal -++++listBoxOption name='Second group item 1' setSize=2 posInSet=1 selected=false -++++listBoxOption name='Second group item 2' setSize=2 posInSet=2 selected=false \ No newline at end of file +++++listBoxOption name='Second group item 1' setSize=4 posInSet=3 selected=false +++++listBoxOption name='Second group item 2' setSize=4 posInSet=4 selected=false
diff --git a/content/test/data/accessibility/aria/aria-posinset-expected-blink.txt b/content/test/data/accessibility/aria/aria-posinset-expected-blink.txt index e4e8860..b3a039bb 100644 --- a/content/test/data/accessibility/aria/aria-posinset-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-posinset-expected-blink.txt
@@ -1,14 +1,14 @@ rootWebArea -++article setSize=2 posInSet=1 +++article setSize=0 posInSet=0 ++++staticText name='This is an ARIA article 1.' ++++++inlineTextBox name='This is an ARIA article 1.' -++article setSize=2 posInSet=2 +++article setSize=0 posInSet=0 ++++staticText name='This is an ARIA article 2.' ++++++inlineTextBox name='This is an ARIA article 2.' -++listBox +++listBox setSize=2 ++++listBoxOption name='Item 1' setSize=2 posInSet=1 selected=false ++++listBoxOption name='Item 2' setSize=2 posInSet=2 selected=false -++listBox +++listBox setSize=2 ++++listBoxOption name='Item 1' setSize=2 posInSet=1 selected=false ++++listBoxOption name='Item 2' setSize=2 posInSet=2 selected=false ++form @@ -28,7 +28,7 @@ ++radioButton setSize=2 posInSet=2 checkedState=false ++staticText name='Banana' ++++inlineTextBox name='Banana' -++group name='Cake' +++group name='Cake' setSize=0 ++++legend ++++++staticText name='Cake' ++++++++inlineTextBox name='Cake' @@ -46,4 +46,4 @@ ++++++++inlineTextBox name='<newline>' ++++++radioButton name='blue' setSize=1 posInSet=1 checkedState=false ++staticText name='Done' -++++inlineTextBox name='Done' \ No newline at end of file +++++inlineTextBox name='Done'
diff --git a/content/test/data/accessibility/aria/aria-posinset-expected-win.txt b/content/test/data/accessibility/aria/aria-posinset-expected-win.txt index 5b1bab1..f52889c 100644 --- a/content/test/data/accessibility/aria/aria-posinset-expected-win.txt +++ b/content/test/data/accessibility/aria/aria-posinset-expected-win.txt
@@ -1,12 +1,12 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++ROLE_SYSTEM_DOCUMENT READONLY setsize:2 posinset:1 +++ROLE_SYSTEM_DOCUMENT READONLY setsize:0 posinset:0 ++++ROLE_SYSTEM_STATICTEXT name='This is an ARIA article 1.' -++ROLE_SYSTEM_DOCUMENT READONLY setsize:2 posinset:2 +++ROLE_SYSTEM_DOCUMENT READONLY setsize:0 posinset:0 ++++ROLE_SYSTEM_STATICTEXT name='This is an ARIA article 2.' -++ROLE_SYSTEM_LIST +++ROLE_SYSTEM_LIST setsize:2 ++++ROLE_SYSTEM_LISTITEM name='Item 1' FOCUSABLE setsize:2 posinset:1 ++++ROLE_SYSTEM_LISTITEM name='Item 2' FOCUSABLE setsize:2 posinset:2 -++ROLE_SYSTEM_LIST +++ROLE_SYSTEM_LIST setsize:2 ++++ROLE_SYSTEM_LISTITEM name='Item 1' FOCUSABLE setsize:2 posinset:1 ++++ROLE_SYSTEM_LISTITEM name='Item 2' FOCUSABLE setsize:2 posinset:2 ++IA2_ROLE_FORM @@ -20,7 +20,7 @@ ++ROLE_SYSTEM_WHITESPACE name='<newline>' ++ROLE_SYSTEM_RADIOBUTTON FOCUSABLE IA2_STATE_CHECKABLE setsize:2 posinset:2 checkable:true ++ROLE_SYSTEM_STATICTEXT name='Banana' -++ROLE_SYSTEM_GROUPING name='Cake' +++ROLE_SYSTEM_GROUPING name='Cake' setsize:0 ++++IA2_ROLE_LABEL ++++++ROLE_SYSTEM_STATICTEXT name='Cake' ++++ROLE_SYSTEM_RADIOBUTTON name='Chiffon cakes' CHECKED FOCUSABLE IA2_STATE_CHECKABLE setsize:2 posinset:1 checkable:true @@ -33,4 +33,4 @@ ++++++++ROLE_SYSTEM_STATICTEXT name='red' ++++++ROLE_SYSTEM_WHITESPACE name='<newline>' ++++++ROLE_SYSTEM_RADIOBUTTON name='blue' FOCUSABLE IA2_STATE_CHECKABLE setsize:1 posinset:1 checkable:true -++ROLE_SYSTEM_STATICTEXT name='Done' \ No newline at end of file +++ROLE_SYSTEM_STATICTEXT name='Done'
diff --git a/content/test/data/accessibility/aria/aria-setsize-expected-blink.txt b/content/test/data/accessibility/aria/aria-setsize-expected-blink.txt index bb8a597a..4459055 100644 --- a/content/test/data/accessibility/aria/aria-setsize-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-setsize-expected-blink.txt
@@ -1,12 +1,12 @@ rootWebArea -++listBox +++listBox setSize=4 ++++listBoxOption name='Item 1' setSize=4 posInSet=1 selected=false ++++listBoxOption name='Item 2' setSize=4 posInSet=2 selected=false ++++listBoxOption name='Item 3' setSize=4 posInSet=3 selected=false ++++listBoxOption name='Item 4' setSize=4 posInSet=4 selected=false -++listBox +++listBox setSize=5 ++++listBoxOption name='Item 1' setSize=5 posInSet=1 selected=false ++++listBoxOption name='Item 2' setSize=5 posInSet=2 selected=false ++++listBoxOption name='Item 3' setSize=5 posInSet=3 selected=false ++++listBoxOption name='Item 4' setSize=5 posInSet=4 selected=false -++++listBoxOption name='Item 5' setSize=5 posInSet=5 selected=false \ No newline at end of file +++++listBoxOption name='Item 5' setSize=5 posInSet=5 selected=false
diff --git a/content/test/data/accessibility/aria/aria-setsize-expected-win.txt b/content/test/data/accessibility/aria/aria-setsize-expected-win.txt index 6cae42b..0874fd57 100644 --- a/content/test/data/accessibility/aria/aria-setsize-expected-win.txt +++ b/content/test/data/accessibility/aria/aria-setsize-expected-win.txt
@@ -1,10 +1,10 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++ROLE_SYSTEM_LIST +++ROLE_SYSTEM_LIST setsize:4 ++++ROLE_SYSTEM_LISTITEM name='Item 1' FOCUSABLE setsize:4 posinset:1 ++++ROLE_SYSTEM_LISTITEM name='Item 2' FOCUSABLE setsize:4 posinset:2 ++++ROLE_SYSTEM_LISTITEM name='Item 3' FOCUSABLE setsize:4 posinset:3 ++++ROLE_SYSTEM_LISTITEM name='Item 4' FOCUSABLE setsize:4 posinset:4 -++ROLE_SYSTEM_LIST +++ROLE_SYSTEM_LIST setsize:5 ++++ROLE_SYSTEM_LISTITEM name='Item 1' FOCUSABLE setsize:5 posinset:1 ++++ROLE_SYSTEM_LISTITEM name='Item 2' FOCUSABLE setsize:5 posinset:2 ++++ROLE_SYSTEM_LISTITEM name='Item 3' FOCUSABLE setsize:5 posinset:3
diff --git a/content/test/data/accessibility/aria/aria-tab-expected-blink.txt b/content/test/data/accessibility/aria/aria-tab-expected-blink.txt index c92853c..e8cd121 100644 --- a/content/test/data/accessibility/aria/aria-tab-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-tab-expected-blink.txt
@@ -1,4 +1,4 @@ rootWebArea -++tabList horizontal +++tabList horizontal setSize=2 ++++tab name='Tab 1' setSize=2 posInSet=1 selected=false -++++tab name='Tab 2' setSize=2 posInSet=2 selected=false \ No newline at end of file +++++tab name='Tab 2' setSize=2 posInSet=2 selected=false
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-blink.txt b/content/test/data/accessibility/aria/aria-tree-expected-blink.txt index d9ec7e3a..df2a948d 100644 --- a/content/test/data/accessibility/aria/aria-tree-expected-blink.txt +++ b/content/test/data/accessibility/aria/aria-tree-expected-blink.txt
@@ -1,15 +1,15 @@ rootWebArea -++tree +++tree setSize=2 ++++treeItem name='Animals' hierarchicalLevel=1 setSize=2 posInSet=1 checkedState=mixed selected=false ++++++link name='Animals' ++++++++staticText name='Animals' ++++++++++inlineTextBox name='Animals' -++++++group +++++++group setSize=2 ++++++++treeItem name='Domesticated' hierarchicalLevel=2 setSize=2 posInSet=1 selected=false ++++++++++link name='Domesticated' ++++++++++++staticText name='Domesticated' ++++++++++++++inlineTextBox name='Domesticated' -++++++++++group +++++++++++group setSize=2 ++++++++++++treeItem name='Dog' hierarchicalLevel=3 setSize=2 posInSet=1 checkedState=true selected=false ++++++++++++++link name='Dog' ++++++++++++++++staticText name='Dog'
diff --git a/content/test/data/accessibility/aria/aria-tree-expected-win.txt b/content/test/data/accessibility/aria/aria-tree-expected-win.txt index 16010b8..c0f2ac17 100644 --- a/content/test/data/accessibility/aria/aria-tree-expected-win.txt +++ b/content/test/data/accessibility/aria/aria-tree-expected-win.txt
@@ -1,13 +1,13 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE -++ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL +++ROLE_SYSTEM_OUTLINE IA2_STATE_VERTICAL setsize:2 ++++ROLE_SYSTEM_OUTLINEITEM name='Animals' MIXED IA2_STATE_CHECKABLE level:1 setsize:2 posinset:1 checkable:true ++++++ROLE_SYSTEM_LINK name='Animals' FOCUSABLE ++++++++ROLE_SYSTEM_STATICTEXT name='Animals' -++++++ROLE_SYSTEM_GROUPING +++++++ROLE_SYSTEM_GROUPING setsize:2 ++++++++ROLE_SYSTEM_OUTLINEITEM name='Domesticated' level:2 setsize:2 posinset:1 ++++++++++ROLE_SYSTEM_LINK name='Domesticated' FOCUSABLE ++++++++++++ROLE_SYSTEM_STATICTEXT name='Domesticated' -++++++++++ROLE_SYSTEM_GROUPING +++++++++++ROLE_SYSTEM_GROUPING setsize:2 ++++++++++++ROLE_SYSTEM_OUTLINEITEM name='Dog' CHECKED IA2_STATE_CHECKABLE level:3 setsize:2 posinset:1 checkable:true ++++++++++++++ROLE_SYSTEM_LINK name='Dog' FOCUSABLE ++++++++++++++++ROLE_SYSTEM_STATICTEXT name='Dog'
diff --git a/content/test/data/accessibility/event/add-subtree-expected-win.txt b/content/test/data/accessibility/event/add-subtree-expected-win.txt index de590142..57b78be 100644 --- a/content/test/data/accessibility/event/add-subtree-expected-win.txt +++ b/content/test/data/accessibility/event/add-subtree-expected-win.txt
@@ -1,3 +1,3 @@ EVENT_OBJECT_REORDER on <ul> role=ROLE_SYSTEM_LIST SetSize=3 EVENT_OBJECT_SHOW on <li> role=ROLE_SYSTEM_LISTITEM PosInSet=3 SetSize=3 -IA2_EVENT_TEXT_INSERTED on <ul> role=ROLE_SYSTEM_LIST SetSize=2 new_text={'<obj>' start=2 end=3} +IA2_EVENT_TEXT_INSERTED on <ul> role=ROLE_SYSTEM_LIST SetSize=3 new_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/remove-hidden-attribute-expected-win.txt b/content/test/data/accessibility/event/remove-hidden-attribute-expected-win.txt index 7c485e7..73cb5b6a 100644 --- a/content/test/data/accessibility/event/remove-hidden-attribute-expected-win.txt +++ b/content/test/data/accessibility/event/remove-hidden-attribute-expected-win.txt
@@ -1,3 +1,3 @@ EVENT_OBJECT_REORDER on <div> role=ROLE_SYSTEM_LIST SetSize=3 EVENT_OBJECT_SHOW on <div#item3> role=ROLE_SYSTEM_LISTITEM name="Item 3" PosInSet=3 SetSize=3 -IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_LIST SetSize=2 new_text={'<obj>' start=2 end=3} +IA2_EVENT_TEXT_INSERTED on <div> role=ROLE_SYSTEM_LIST SetSize=3 new_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-win.txt b/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-win.txt index 1200268a..3dadf9f 100644 --- a/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-win.txt +++ b/content/test/data/accessibility/event/remove-hidden-attribute-subtree-expected-win.txt
@@ -1,3 +1,3 @@ EVENT_OBJECT_REORDER on <ul> role=ROLE_SYSTEM_LIST SetSize=3 EVENT_OBJECT_SHOW on <li#item3> role=ROLE_SYSTEM_LISTITEM PosInSet=3 SetSize=3 -IA2_EVENT_TEXT_INSERTED on <ul> role=ROLE_SYSTEM_LIST SetSize=2 new_text={'<obj>' start=2 end=3} +IA2_EVENT_TEXT_INSERTED on <ul> role=ROLE_SYSTEM_LIST SetSize=3 new_text={'<obj>' start=2 end=3}
diff --git a/content/test/data/accessibility/html/li-expected-auralinux.txt b/content/test/data/accessibility/html/li-expected-auralinux.txt index ef3966a..8ddbd7ec 100644 --- a/content/test/data/accessibility/html/li-expected-auralinux.txt +++ b/content/test/data/accessibility/html/li-expected-auralinux.txt
@@ -1,5 +1,5 @@ [document web] -++[list] display:block +++[list] display:block setsize:3 ++++[list item] display:list-item posinset:1 setsize:3 ++++++[static] name='• ' ++++++[text] name='Item 1' display:list-item
diff --git a/content/test/data/accessibility/html/li-expected-blink.txt b/content/test/data/accessibility/html/li-expected-blink.txt index 4cfbfc37..9895cd6 100644 --- a/content/test/data/accessibility/html/li-expected-blink.txt +++ b/content/test/data/accessibility/html/li-expected-blink.txt
@@ -1,5 +1,5 @@ rootWebArea -++list display='block' +++list display='block' setSize=3 ++++listItem display='list-item' setSize=3 posInSet=1 ++++++listMarker name='• ' ++++++staticText display='list-item' name='Item 1'
diff --git a/content/test/data/accessibility/html/optgroup-expected-auralinux.txt b/content/test/data/accessibility/html/optgroup-expected-auralinux.txt index 0d838b60..64b1d73 100644 --- a/content/test/data/accessibility/html/optgroup-expected-auralinux.txt +++ b/content/test/data/accessibility/html/optgroup-expected-auralinux.txt
@@ -1,15 +1,15 @@ [document web] enabled ++[section] enabled -++++[list box] enabled -++++++[panel] name='Enabled' enabled xml-roles:group +++++[list box] enabled setsize:8 +++++++[panel] name='Enabled' enabled setsize:0 xml-roles:group ++++++++[text] name='Enabled' enabled -++++++[list item] name='One' enabled selectable posinset:1 setsize:4 -++++++[list item] name='Two' enabled selectable posinset:2 setsize:4 -++++++[list item] name='Three' enabled selectable posinset:3 setsize:4 -++++++[list item] name='Four' enabled selectable posinset:4 setsize:4 -++++++[panel] name='Disabled' enabled xml-roles:group +++++++[list item] name='One' enabled selectable posinset:1 setsize:8 +++++++[list item] name='Two' enabled selectable posinset:2 setsize:8 +++++++[list item] name='Three' enabled selectable posinset:3 setsize:8 +++++++[list item] name='Four' enabled selectable posinset:4 setsize:8 +++++++[panel] name='Disabled' enabled setsize:0 xml-roles:group ++++++++[text] name='Disabled' enabled -++++++[list item] name='One' posinset:1 setsize:4 -++++++[list item] name='Two' posinset:2 setsize:4 -++++++[list item] name='Three' posinset:3 setsize:4 -++++++[list item] name='Four' posinset:4 setsize:4 +++++++[list item] name='One' posinset:5 setsize:8 +++++++[list item] name='Two' posinset:6 setsize:8 +++++++[list item] name='Three' posinset:7 setsize:8 +++++++[list item] name='Four' posinset:8 setsize:8
diff --git a/content/test/data/accessibility/html/optgroup-expected-blink.txt b/content/test/data/accessibility/html/optgroup-expected-blink.txt index ecbaeabc..7769636 100644 --- a/content/test/data/accessibility/html/optgroup-expected-blink.txt +++ b/content/test/data/accessibility/html/optgroup-expected-blink.txt
@@ -1,17 +1,17 @@ rootWebArea ++genericContainer -++++listBox -++++++group name='Enabled' +++++listBox setSize=8 +++++++group name='Enabled' setSize=0 ++++++++staticText name='Enabled' ++++++++++inlineTextBox name='Enabled' -++++++listBoxOption name='One' setSize=4 posInSet=1 selected=false -++++++listBoxOption name='Two' setSize=4 posInSet=2 selected=false -++++++listBoxOption name='Three' setSize=4 posInSet=3 selected=false -++++++listBoxOption name='Four' setSize=4 posInSet=4 selected=false -++++++group name='Disabled' +++++++listBoxOption name='One' setSize=8 posInSet=1 selected=false +++++++listBoxOption name='Two' setSize=8 posInSet=2 selected=false +++++++listBoxOption name='Three' setSize=8 posInSet=3 selected=false +++++++listBoxOption name='Four' setSize=8 posInSet=4 selected=false +++++++group name='Disabled' setSize=0 ++++++++staticText name='Disabled' ++++++++++inlineTextBox name='Disabled' -++++++listBoxOption name='One' restriction=disabled setSize=4 posInSet=1 -++++++listBoxOption name='Two' restriction=disabled setSize=4 posInSet=2 -++++++listBoxOption name='Three' restriction=disabled setSize=4 posInSet=3 -++++++listBoxOption name='Four' restriction=disabled setSize=4 posInSet=4 \ No newline at end of file +++++++listBoxOption name='One' restriction=disabled setSize=8 posInSet=5 +++++++listBoxOption name='Two' restriction=disabled setSize=8 posInSet=6 +++++++listBoxOption name='Three' restriction=disabled setSize=8 posInSet=7 +++++++listBoxOption name='Four' restriction=disabled setSize=8 posInSet=8
diff --git a/content/test/data/accessibility/html/select-expected-auralinux.txt b/content/test/data/accessibility/html/select-expected-auralinux.txt index 345a762f..596ea75 100644 --- a/content/test/data/accessibility/html/select-expected-auralinux.txt +++ b/content/test/data/accessibility/html/select-expected-auralinux.txt
@@ -1,25 +1,25 @@ [document web] ++[section] ++++[combo box] expandable haspopup:menu -++++++[menu] +++++++[menu] setsize:3 ++++++++[menu item] name='Placeholder option' selectable selected posinset:1 setsize:3 ++++++++[menu item] name='Option 1' selectable posinset:2 setsize:3 ++++++++[menu item] name='Option 2' selectable posinset:3 setsize:3 ++++[combo box] expandable haspopup:menu -++++++[menu] +++++++[menu] setsize:3 ++++++++[menu item] name='Option 1' selectable posinset:1 setsize:3 ++++++++[menu item] name='Option 2' selectable selected posinset:2 setsize:3 ++++++++[menu item] name='Option 3' selectable posinset:3 setsize:3 ++++[combo box] expandable required haspopup:menu -++++++[menu] +++++++[menu] setsize:3 ++++++++[menu item] name='Option 1' selectable selected posinset:1 setsize:3 ++++++++[menu item] name='Option 2' selectable posinset:2 setsize:3 ++++++++[menu item] name='Option 3' selectable posinset:3 setsize:3 -++++[list box] multiselectable +++++[list box] multiselectable setsize:3 ++++++[list item] name='Option 1' selectable posinset:1 setsize:3 ++++++[list item] name='Option 2' selectable posinset:2 setsize:3 ++++++[list item] name='Option 3' selectable posinset:3 setsize:3 -++++[list box] +++++[list box] setsize:3 ++++++[list item] name='Option 1' selectable posinset:1 setsize:3 ++++++[list item] name='Option 2' selectable posinset:2 setsize:3 ++++++[list item] name='Option 3' selectable posinset:3 setsize:3
diff --git a/content/test/data/accessibility/html/select-expected-blink.txt b/content/test/data/accessibility/html/select-expected-blink.txt index 8508b8c..43677b6 100644 --- a/content/test/data/accessibility/html/select-expected-blink.txt +++ b/content/test/data/accessibility/html/select-expected-blink.txt
@@ -1,25 +1,25 @@ rootWebArea focusable ++genericContainer ++++popUpButton collapsed focusable value='Placeholder option' haspopup=menu -++++++menuListPopup invisible +++++++menuListPopup invisible setSize=3 ++++++++menuListOption focusable name='Placeholder option' setSize=3 posInSet=1 selected=true ++++++++menuListOption focusable invisible name='Option 1' setSize=3 posInSet=2 selected=false ++++++++menuListOption focusable invisible name='Option 2' setSize=3 posInSet=3 selected=false ++++popUpButton collapsed focusable value='Option 2' haspopup=menu -++++++menuListPopup invisible +++++++menuListPopup invisible setSize=3 ++++++++menuListOption focusable invisible name='Option 1' setSize=3 posInSet=1 selected=false ++++++++menuListOption focusable name='Option 2' setSize=3 posInSet=2 selected=true ++++++++menuListOption focusable invisible name='Option 3' setSize=3 posInSet=3 selected=false ++++popUpButton collapsed focusable required value='Option 1' haspopup=menu -++++++menuListPopup invisible +++++++menuListPopup invisible setSize=3 ++++++++menuListOption focusable name='Option 1' setSize=3 posInSet=1 selected=true ++++++++menuListOption focusable invisible name='Option 2' setSize=3 posInSet=2 selected=false ++++++++menuListOption focusable invisible name='Option 3' setSize=3 posInSet=3 selected=false -++++listBox focusable multiselectable +++++listBox focusable multiselectable setSize=3 ++++++listBoxOption focusable name='Option 1' setSize=3 posInSet=1 selected=false ++++++listBoxOption focusable name='Option 2' setSize=3 posInSet=2 selected=false ++++++listBoxOption focusable name='Option 3' setSize=3 posInSet=3 selected=false -++++listBox focusable +++++listBox focusable setSize=3 ++++++listBoxOption focusable name='Option 1' setSize=3 posInSet=1 selected=false ++++++listBoxOption focusable name='Option 2' setSize=3 posInSet=2 selected=false ++++++listBoxOption focusable name='Option 3' setSize=3 posInSet=3 selected=false
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py index 9e5a03d..2508f192 100644 --- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -95,9 +95,6 @@ 'integer-cubemap-specification-order-bug.html', bug=905003) # owner:cwallez, test might be buggy - # Need to implement new lifetime/deletion semantics. - self.Fail('conformance2/vertex_arrays/vertex-array-object.html', bug=739604) - # The following actually passes on gl_passthrough and also Mac Intel with # command buffer. self.Fail('deqp/functional/gles3/shadertexturefunction/' +
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index de61db9..3351133 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -95,9 +95,6 @@ # ======================== # Fails on all platforms - # Need to implement new lifetime/deletion semantics. - self.Fail('conformance/extensions/oes-vertex-array-object.html', bug=739604) - # Need to add detection of feedback loops with multiple render targets. self.Fail('conformance/rendering/rendering-sampling-feedback-loop.html', bug=660844) @@ -337,9 +334,8 @@ ['win10', 'intel', 'opengl', 'no_passthrough'], bug=680797) self.Fail('conformance/extensions/oes-texture-half-float-with-canvas.html', ['win10', 'intel', 'opengl', 'no_passthrough'], bug=680797) - # TODO(kbr): re-enable after fixing lifetime semantics. crbug.com/739604 - # self.Fail('conformance/extensions/oes-vertex-array-object.html', - # ['win10', 'intel', 'opengl'], bug=680797) + self.Fail('conformance/extensions/oes-vertex-array-object.html', + ['win10', 'intel', 'opengl'], bug=680797) self.Fail('conformance/glsl/bugs/' + 'array-of-struct-with-int-first-position.html', ['win10', 'intel', 'opengl'], bug=680797)
diff --git a/docs/how_to_add_your_feature_flag.md b/docs/how_to_add_your_feature_flag.md index 39a54cb..a27e24d6 100644 --- a/docs/how_to_add_your_feature_flag.md +++ b/docs/how_to_add_your_feature_flag.md
@@ -47,6 +47,8 @@ autoninja -C out/Default unit_tests # Run AboutFlagsHistogramTest.CheckHistograms ./out/Default/unit_tests --gtest_filter=AboutFlagsHistogramTest.CheckHistograms +# Run AboutFlagsHistogramTest.CheckHistograms on Android +./out/Default/bin/run_unit_tests --gtest_filter=AboutFlagsHistogramTest.CheckHistograms ``` That test will ask you to add several entries to enums.xml.
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index bdea2ea02..71533a0d 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -1368,6 +1368,7 @@ AUTOTESTPRIVATE_SENDASSISTANTTEXTQUERY = 1305, AUTOTESTPRIVATE_SETCROSTINIAPPSCALED = 1306, ACTIVITYLOGPRIVATE_DELETEACTIVITIESBYEXTENSION = 1307, + ACCESSIBILITY_PRIVATE_FORWARDKEYEVENTSTOSWITCHACCESS = 1308, // Last entry: Add new entries above, then run: // python tools/metrics/histograms/update_extension_histograms.py ENUM_BOUNDARY
diff --git a/extensions/browser/url_loader_factory_manager.cc b/extensions/browser/url_loader_factory_manager.cc index 3ad1140..c56ef73 100644 --- a/extensions/browser/url_loader_factory_manager.cc +++ b/extensions/browser/url_loader_factory_manager.cc
@@ -66,7 +66,6 @@ "0CD842E367BA8D9ECE3A2F68448B338AF5C84F88", "0EBA158DA6EC99B8E71FBDB7CA7CA4DF1C707B0F", "0EBCD86FC44873101E247C81BE81662AB1379738", - "133E65ABB919CEC935A54700136E6405BDF1FF25", "16A81AEA09A67B03F7AEA5B957D24A4095E764BE", "177508B365CBF1610CC2B53707749D79272F2F0B", "1AB9CC404876117F49135E67BAD813F935AAE9BA",
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc index 085fcdb..f44786505 100644 --- a/extensions/common/extension_features.cc +++ b/extensions/common/extension_features.cc
@@ -11,7 +11,7 @@ // https://crbug.com/846346 and DoContentScriptsDependOnRelaxedCorb function in // extensions/browser/url_loader_factory_manager.cc. const base::Feature kBypassCorbOnlyForExtensionsAllowlist{ - "BypassCorbOnlyForExtensionsAllowlist", base::FEATURE_DISABLED_BY_DEFAULT}; + "BypassCorbOnlyForExtensionsAllowlist", base::FEATURE_ENABLED_BY_DEFAULT}; const char kBypassCorbAllowlistParamName[] = "BypassCorbExtensionsAllowlist"; // Enables the use of C++-based extension bindings (instead of JS generation).
diff --git a/extensions/common/manifest_constants.cc b/extensions/common/manifest_constants.cc index 17e168c..b44d3e1 100644 --- a/extensions/common/manifest_constants.cc +++ b/extensions/common/manifest_constants.cc
@@ -32,6 +32,10 @@ const char kContentCapabilities[] = "content_capabilities"; const char kContentScripts[] = "content_scripts"; const char kContentSecurityPolicy[] = "content_security_policy"; +const char kContentSecurityPolicy_ExtensionPagesPath[] = + "content_security_policy.extension_pages"; +const char kContentSecurityPolicy_SandboxedPagesPath[] = + "content_security_policy.sandbox"; const char kConvertedFromUserScript[] = "converted_from_user_script"; const char kCss[] = "css"; const char kCtrlKey[] = "ctrlKey"; @@ -732,6 +736,9 @@ "The \"plugins\" requirement is deprecated."; const char kReservedMessageFound[] = "Reserved key * found in message catalog."; +const char kSandboxPagesCSPKeyNotAllowed[] = + "The Content Security Policy for sandboxed pages should be specified in " + "'content_security_policy.sandbox'."; const char kRulesFileIsInvalid[] = "Invalid value for key '*.*': The provided path is invalid."; const char kTtsGenderIsDeprecated[] =
diff --git a/extensions/common/manifest_constants.h b/extensions/common/manifest_constants.h index 961423e..a9615a3 100644 --- a/extensions/common/manifest_constants.h +++ b/extensions/common/manifest_constants.h
@@ -35,6 +35,8 @@ extern const char kContentCapabilities[]; extern const char kContentScripts[]; extern const char kContentSecurityPolicy[]; +extern const char kContentSecurityPolicy_ExtensionPagesPath[]; +extern const char kContentSecurityPolicy_SandboxedPagesPath[]; extern const char kConvertedFromUserScript[]; extern const char kCss[]; extern const char kCtrlKey[]; @@ -494,6 +496,7 @@ extern const char kPermissionUnknownOrMalformed[]; extern const char kPluginsRequirementDeprecated[]; extern const char kReservedMessageFound[]; +extern const char kSandboxPagesCSPKeyNotAllowed[]; extern const char kRulesFileIsInvalid[]; extern const char kTtsGenderIsDeprecated[]; extern const char kUnrecognizedManifestKey[];
diff --git a/extensions/common/manifest_handlers/csp_info.cc b/extensions/common/manifest_handlers/csp_info.cc index 36c519c..4a641c4 100644 --- a/extensions/common/manifest_handlers/csp_info.cc +++ b/extensions/common/manifest_handlers/csp_info.cc
@@ -35,9 +35,6 @@ "sandbox allow-scripts allow-forms allow-popups allow-modals; " "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"; -const char kExtensionPagesKey[] = "extension_pages"; -const char kExtensionPagesPath[] = "content_security_policy.extension_pages"; - #define PLATFORM_APP_LOCAL_CSP_SOURCES \ "'self' blob: filesystem: data: chrome-extension-resource:" @@ -153,19 +150,35 @@ extension->GetType() == Manifest::TYPE_EXTENSION && GetCurrentChannel() == version_info::Channel::UNKNOWN; if (csp_dictionary_supported && csp && csp->is_dict()) - return ParseCSPDictionary(extension, error, *csp); + return ParseCSPDictionary(extension, error); + // TODO(crbug.com/914224) Disallow the usages below in manifest v3 for + // extensions. return ParseExtensionPagesCSP(extension, error, key, csp) && ParseSandboxCSP(extension, error, keys::kSandboxedPagesCSP, GetManifestPath(extension, keys::kSandboxedPagesCSP)); } bool CSPHandler::ParseCSPDictionary(Extension* extension, - base::string16* error, - const base::Value& csp_dict) { - DCHECK(csp_dict.is_dict()); - return ParseExtensionPagesCSP(extension, error, kExtensionPagesPath, - csp_dict.FindKey(kExtensionPagesKey)); + base::string16* error) { + if (!ParseExtensionPagesCSP( + extension, error, keys::kContentSecurityPolicy_ExtensionPagesPath, + GetManifestPath(extension, + keys::kContentSecurityPolicy_ExtensionPagesPath))) { + return false; + } + + // keys::kSandboxedPagesCSP shouldn't be used when using + // keys::kContentSecurityPolicy as a dictionary. + if (extension->manifest()->HasPath(keys::kSandboxedPagesCSP)) { + *error = base::ASCIIToUTF16(errors::kSandboxPagesCSPKeyNotAllowed); + return false; + } + + return ParseSandboxCSP( + extension, error, keys::kContentSecurityPolicy_SandboxedPagesPath, + GetManifestPath(extension, + keys::kContentSecurityPolicy_SandboxedPagesPath)); } bool CSPHandler::ParseExtensionPagesCSP(
diff --git a/extensions/common/manifest_handlers/csp_info.h b/extensions/common/manifest_handlers/csp_info.h index c2ad9262..636bb6f 100644 --- a/extensions/common/manifest_handlers/csp_info.h +++ b/extensions/common/manifest_handlers/csp_info.h
@@ -55,9 +55,7 @@ private: // Parses the "content_security_policy" dictionary in the manifest. - bool ParseCSPDictionary(Extension* extension, - base::string16* error, - const base::Value& csp_dict); + bool ParseCSPDictionary(Extension* extension, base::string16* error); // Parses the content security policy specified in the manifest for extension // pages.
diff --git a/extensions/common/manifest_handlers/csp_info_unittest.cc b/extensions/common/manifest_handlers/csp_info_unittest.cc index da050fe3..aefff22 100644 --- a/extensions/common/manifest_handlers/csp_info_unittest.cc +++ b/extensions/common/manifest_handlers/csp_info_unittest.cc
@@ -110,7 +110,7 @@ EXPECT_TYPE_ERROR); } -TEST_F(CSPInfoUnitTest, CSPDictionaryKey) { +TEST_F(CSPInfoUnitTest, CSPDictionary_ExtensionPages) { const char kDefaultCSP[] = "script-src 'self' blob: filesystem: chrome-extension-resource:; " "object-src 'self' blob: filesystem:;"; @@ -122,7 +122,7 @@ {"csp_empty_valid.json", "script-src 'self'; object-src 'self';"}, {"csp_empty_dictionary_valid.json", kDefaultCSP}}; - // Verify that "content_security_policy" key can be used as a dictionary on + // Verify that keys::kContentSecurityPolicy key can be used as a dictionary on // trunk. { ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); @@ -137,8 +137,8 @@ } } - // Verify that "content_security_policy" key can't be used as a dictionary on - // Stable. + // Verify that keys::kContentSecurityPolicy key can't be used as a dictionary + // on Stable. { ScopedCurrentChannel channel(version_info::Channel::STABLE); for (const auto& test_case : cases) { @@ -152,14 +152,63 @@ { ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); - const char* kExtensionPagesKey = "content_security_policy.extension_pages"; Testcase testcases[] = { Testcase("csp_invalid_2.json", - GetInvalidManifestKeyError(kExtensionPagesKey)), + GetInvalidManifestKeyError( + keys::kContentSecurityPolicy_ExtensionPagesPath)), Testcase("csp_invalid_3.json", - GetInvalidManifestKeyError(kExtensionPagesKey))}; + GetInvalidManifestKeyError( + keys::kContentSecurityPolicy_ExtensionPagesPath))}; RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR); } } +TEST_F(CSPInfoUnitTest, CSPDictionary_Sandbox) { + ScopedCurrentChannel channel(version_info::Channel::UNKNOWN); + + const char kCustomSandboxedCSP[] = + "sandbox; script-src 'self'; child-src 'self';"; + const char kDefaultSandboxedPageCSP[] = + "sandbox allow-scripts allow-forms allow-popups allow-modals; " + "script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self';"; + const char kDefaultExtensionPagesCSP[] = + "script-src 'self' blob: filesystem: chrome-extension-resource:; " + "object-src 'self' blob: filesystem:;"; + const char kCustomExtensionPagesCSP[] = "script-src; object-src;"; + + struct { + const char* file_name; + const char* resource_path; + const char* expected_csp; + } success_cases[] = { + {"sandbox_dictionary_1.json", "/test", kCustomSandboxedCSP}, + {"sandbox_dictionary_1.json", "/index", kDefaultExtensionPagesCSP}, + {"sandbox_dictionary_2.json", "/test", kDefaultSandboxedPageCSP}, + {"sandbox_dictionary_2.json", "/index", kCustomExtensionPagesCSP}, + }; + + for (const auto& test_case : success_cases) { + SCOPED_TRACE(base::StringPrintf("%s with path %s", test_case.file_name, + test_case.resource_path)); + scoped_refptr<Extension> extension = + LoadAndExpectSuccess(test_case.file_name); + ASSERT_TRUE(extension); + EXPECT_EQ(test_case.expected_csp, + CSPInfo::GetResourceContentSecurityPolicy( + extension.get(), test_case.resource_path)); + } + + Testcase testcases[] = { + {"sandbox_both_keys.json", errors::kSandboxPagesCSPKeyNotAllowed}, + {"sandbox_csp_with_dictionary.json", + errors::kSandboxPagesCSPKeyNotAllowed}, + {"sandbox_invalid_type.json", + GetInvalidManifestKeyError( + keys::kContentSecurityPolicy_SandboxedPagesPath)}, + {"unsandboxed_csp.json", + GetInvalidManifestKeyError( + keys::kContentSecurityPolicy_SandboxedPagesPath)}}; + RunTestcases(testcases, base::size(testcases), EXPECT_TYPE_ERROR); +} + } // namespace extensions
diff --git a/extensions/test/data/manifest_tests/sandbox_both_keys.json b/extensions/test/data/manifest_tests/sandbox_both_keys.json new file mode 100644 index 0000000..347809d --- /dev/null +++ b/extensions/test/data/manifest_tests/sandbox_both_keys.json
@@ -0,0 +1,12 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "sandbox": { + "pages": ["test"], + "content_security_policy": "sandbox;" + }, + "content_security_policy" : { + "sandbox" : "sandbox; script-src https://www.google.com" + } +}
diff --git a/extensions/test/data/manifest_tests/sandbox_csp_with_dictionary.json b/extensions/test/data/manifest_tests/sandbox_csp_with_dictionary.json new file mode 100644 index 0000000..ffceab8 --- /dev/null +++ b/extensions/test/data/manifest_tests/sandbox_csp_with_dictionary.json
@@ -0,0 +1,12 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "sandbox": { + "pages": ["test"], + "content_security_policy": "sandbox;" + }, + "content_security_policy" : { + "extension_pages" : "script-src google.com;" + } +}
diff --git a/extensions/test/data/manifest_tests/sandbox_dictionary_1.json b/extensions/test/data/manifest_tests/sandbox_dictionary_1.json new file mode 100644 index 0000000..daa54d4 --- /dev/null +++ b/extensions/test/data/manifest_tests/sandbox_dictionary_1.json
@@ -0,0 +1,11 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "sandbox": { + "pages": ["test"] + }, + "content_security_policy" : { + "sandbox" : "sandbox; script-src https://www.google.com" + } +}
diff --git a/extensions/test/data/manifest_tests/sandbox_dictionary_2.json b/extensions/test/data/manifest_tests/sandbox_dictionary_2.json new file mode 100644 index 0000000..0c5fff5 --- /dev/null +++ b/extensions/test/data/manifest_tests/sandbox_dictionary_2.json
@@ -0,0 +1,11 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "sandbox": { + "pages": ["test"] + }, + "content_security_policy" : { + "extension_pages" : "script-src; object-src;" + } +}
diff --git a/extensions/test/data/manifest_tests/sandbox_invalid_type.json b/extensions/test/data/manifest_tests/sandbox_invalid_type.json new file mode 100644 index 0000000..0f959d0 --- /dev/null +++ b/extensions/test/data/manifest_tests/sandbox_invalid_type.json
@@ -0,0 +1,11 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "sandbox": { + "pages": ["test"] + }, + "content_security_policy" : { + "sandbox" : [] + } +}
diff --git a/extensions/test/data/manifest_tests/unsandboxed_csp.json b/extensions/test/data/manifest_tests/unsandboxed_csp.json new file mode 100644 index 0000000..35d70e6 --- /dev/null +++ b/extensions/test/data/manifest_tests/unsandboxed_csp.json
@@ -0,0 +1,11 @@ +{ + "name": "test", + "version": "0.1", + "manifest_version": 2, + "sandbox": { + "pages": ["test"] + }, + "content_security_policy" : { + "sandbox" : "script-src https://www.google.com" + } +}
diff --git a/gpu/command_buffer/client/client_transfer_cache.cc b/gpu/command_buffer/client/client_transfer_cache.cc index 9e2e930d..b762dac 100644 --- a/gpu/command_buffer/client/client_transfer_cache.cc +++ b/gpu/command_buffer/client/client_transfer_cache.cc
@@ -11,7 +11,7 @@ ClientTransferCache::~ClientTransferCache() = default; void* ClientTransferCache::MapEntry(MappedMemoryManager* mapped_memory, - size_t size) { + uint32_t size) { DCHECK(!mapped_ptr_); DCHECK(!transfer_buffer_ptr_); mapped_ptr_.emplace(size, client_->cmd_buffer_helper(), mapped_memory); @@ -24,7 +24,7 @@ void* ClientTransferCache::MapTransferBufferEntry( TransferBufferInterface* transfer_buffer, - size_t size) { + uint32_t size) { DCHECK(!mapped_ptr_); DCHECK(!transfer_buffer_ptr_); transfer_buffer_ptr_.emplace(size, client_->cmd_buffer_helper(), @@ -64,7 +64,7 @@ uint32_t id, uint32_t shm_id, uint32_t shm_offset, - size_t size) { + uint32_t size) { DCHECK(!mapped_ptr_); EntryKey key(type, id);
diff --git a/gpu/command_buffer/client/client_transfer_cache.h b/gpu/command_buffer/client/client_transfer_cache.h index 45325e1..96f6a919 100644 --- a/gpu/command_buffer/client/client_transfer_cache.h +++ b/gpu/command_buffer/client/client_transfer_cache.h
@@ -79,7 +79,7 @@ uint32_t id, uint32_t shm_id, uint32_t shm_offset, - size_t size); + uint32_t size); // Similar to AddTransferCacheEntry() but doesn't use |client_| to trigger the // creation of the service-side cache entry. Instead, it calls @@ -97,9 +97,9 @@ base::OnceCallback<void(ClientDiscardableHandle)> create_entry_cb); // Map(of either type) must always be followed by an Unmap. - void* MapEntry(MappedMemoryManager* mapped_memory, size_t size); + void* MapEntry(MappedMemoryManager* mapped_memory, uint32_t size); void* MapTransferBufferEntry(TransferBufferInterface* transfer_buffer, - size_t size); + uint32_t size); void UnmapAndCreateEntry(uint32_t type, uint32_t id); bool LockEntry(uint32_t type, uint32_t id); void UnlockEntries(const std::vector<std::pair<uint32_t, uint32_t>>& entries);
diff --git a/gpu/command_buffer/client/context_support.h b/gpu/command_buffer/client/context_support.h index 3e4fed2..a3438f75 100644 --- a/gpu/command_buffer/client/context_support.h +++ b/gpu/command_buffer/client/context_support.h
@@ -116,7 +116,7 @@ // Maps a buffer that will receive serialized data for an entry to be created. // Returns nullptr on failure. If success, must be paired with a call to // UnmapAndCreateTransferCacheEntry. - virtual void* MapTransferCacheEntry(size_t serialized_size) = 0; + virtual void* MapTransferCacheEntry(uint32_t serialized_size) = 0; // Unmaps the buffer and creates a transfer cache entry with the serialized // data.
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index e857907..9a659301 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -6402,7 +6402,7 @@ return manager->TextureIsDeletedForTracing(texture_id); } -void* GLES2Implementation::MapTransferCacheEntry(size_t serialized_size) { +void* GLES2Implementation::MapTransferCacheEntry(uint32_t serialized_size) { NOTREACHED(); return nullptr; }
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 0858127..174431b 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -136,7 +136,7 @@ uint32_t texture_id) override; bool ThreadsafeDiscardableTextureIsDeletedForTracing( uint32_t texture_id) override; - void* MapTransferCacheEntry(size_t serialized_size) override; + void* MapTransferCacheEntry(uint32_t serialized_size) override; void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override; bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override; void UnlockTransferCacheEntries(
diff --git a/gpu/command_buffer/client/raster_implementation.cc b/gpu/command_buffer/client/raster_implementation.cc index 02db32f..4f99136 100644 --- a/gpu/command_buffer/client/raster_implementation.cc +++ b/gpu/command_buffer/client/raster_implementation.cc
@@ -115,7 +115,7 @@ size_t CreateEntryInternal(const cc::ClientTransferCacheEntry& entry, char* memory) final { - size_t size = entry.SerializedSize(); + uint32_t size = entry.SerializedSize(); // Cap the entries inlined to a specific size. if (size <= ri_->max_inlined_entry_size_ && ri_->raster_mapped_buffer_) { size_t written = InlineEntry(entry, memory); @@ -154,7 +154,7 @@ DCHECK(buffer->BelongsToBuffer(memory)); size_t memory_offset = memory - static_cast<char*>(buffer->address()); - size_t bytes_to_write = entry.SerializedSize(); + uint32_t bytes_to_write = entry.SerializedSize(); size_t bytes_remaining = buffer->size() - memory_offset; DCHECK_GT(bytes_to_write, 0u); @@ -481,7 +481,7 @@ return false; } -void* RasterImplementation::MapTransferCacheEntry(size_t serialized_size) { +void* RasterImplementation::MapTransferCacheEntry(uint32_t serialized_size) { // Prefer to use transfer buffer when possible, since transfer buffer // allocations are much cheaper. if (raster_mapped_buffer_ ||
diff --git a/gpu/command_buffer/client/raster_implementation.h b/gpu/command_buffer/client/raster_implementation.h index 681859f..d01b436 100644 --- a/gpu/command_buffer/client/raster_implementation.h +++ b/gpu/command_buffer/client/raster_implementation.h
@@ -163,7 +163,7 @@ uint32_t texture_id) override; bool ThreadsafeDiscardableTextureIsDeletedForTracing( uint32_t texture_id) override; - void* MapTransferCacheEntry(size_t serialized_size) override; + void* MapTransferCacheEntry(uint32_t serialized_size) override; void UnmapAndCreateTransferCacheEntry(uint32_t type, uint32_t id) override; bool ThreadsafeLockTransferCacheEntry(uint32_t type, uint32_t id) override; void UnlockTransferCacheEntries(
diff --git a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc index 4737c2f1..4dc4429 100644 --- a/gpu/command_buffer/client/raster_implementation_gles_unittest.cc +++ b/gpu/command_buffer/client/raster_implementation_gles_unittest.cc
@@ -206,7 +206,7 @@ uint32_t texture_id) override { return false; } - void* MapTransferCacheEntry(size_t serialized_size) override { + void* MapTransferCacheEntry(uint32_t serialized_size) override { mapped_transfer_cache_entry_.reset(new char[serialized_size]); return mapped_transfer_cache_entry_.get(); }
diff --git a/gpu/config/gpu_preferences.h b/gpu/config/gpu_preferences.h index 1d5d6c0c..79965fe 100644 --- a/gpu/config/gpu_preferences.h +++ b/gpu/config/gpu_preferences.h
@@ -101,6 +101,9 @@ bool log_gpu_control_list_decisions = false; + // Enable exporting of events to ETW (on Windows). + bool enable_trace_export_events_to_etw = false; + // =================================== // Settings from //gpu/command_buffer/service/gpu_switches.cc
diff --git a/gpu/config/gpu_preferences_unittest.cc b/gpu/config/gpu_preferences_unittest.cc index d31ea56..260ef9ce3 100644 --- a/gpu/config/gpu_preferences_unittest.cc +++ b/gpu/config/gpu_preferences_unittest.cc
@@ -35,6 +35,8 @@ right.disable_software_rasterizer); EXPECT_EQ(left.log_gpu_control_list_decisions, right.log_gpu_control_list_decisions); + EXPECT_EQ(left.enable_trace_export_events_to_etw, + right.enable_trace_export_events_to_etw); EXPECT_EQ(left.compile_shader_always_succeeds, right.compile_shader_always_succeeds); EXPECT_EQ(left.disable_gl_error_limit, right.disable_gl_error_limit); @@ -125,6 +127,7 @@ GPU_PREFERENCES_FIELD(enable_media_foundation_vea_on_windows7, true) GPU_PREFERENCES_FIELD(disable_software_rasterizer, true) GPU_PREFERENCES_FIELD(log_gpu_control_list_decisions, true) + GPU_PREFERENCES_FIELD(enable_trace_export_events_to_etw, true) GPU_PREFERENCES_FIELD(compile_shader_always_succeeds, true) GPU_PREFERENCES_FIELD(disable_gl_error_limit, true) GPU_PREFERENCES_FIELD(disable_glsl_translator, true)
diff --git a/gpu/ipc/common/gpu_preferences.mojom b/gpu/ipc/common/gpu_preferences.mojom index 61d6150a..fc33fa77 100644 --- a/gpu/ipc/common/gpu_preferences.mojom +++ b/gpu/ipc/common/gpu_preferences.mojom
@@ -34,6 +34,7 @@ bool enable_media_foundation_vea_on_windows7; bool disable_software_rasterizer; bool log_gpu_control_list_decisions; + bool enable_trace_export_events_to_etw; bool compile_shader_always_succeeds; bool disable_gl_error_limit;
diff --git a/gpu/ipc/common/gpu_preferences_struct_traits.h b/gpu/ipc/common/gpu_preferences_struct_traits.h index 22e7524a..29056f6 100644 --- a/gpu/ipc/common/gpu_preferences_struct_traits.h +++ b/gpu/ipc/common/gpu_preferences_struct_traits.h
@@ -76,6 +76,8 @@ out->disable_software_rasterizer = prefs.disable_software_rasterizer(); out->log_gpu_control_list_decisions = prefs.log_gpu_control_list_decisions(); + out->enable_trace_export_events_to_etw = + prefs.enable_trace_export_events_to_etw(); out->compile_shader_always_succeeds = prefs.compile_shader_always_succeeds(); out->disable_gl_error_limit = prefs.disable_gl_error_limit(); @@ -177,6 +179,10 @@ static bool log_gpu_control_list_decisions(const gpu::GpuPreferences& prefs) { return prefs.log_gpu_control_list_decisions; } + static bool enable_trace_export_events_to_etw( + const gpu::GpuPreferences& prefs) { + return prefs.enable_trace_export_events_to_etw; + } static bool compile_shader_always_succeeds(const gpu::GpuPreferences& prefs) { return prefs.compile_shader_always_succeeds; }
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd index 80a50114..2b6f0f7 100644 --- a/ios/chrome/app/strings/ios_strings.grd +++ b/ios/chrome/app/strings/ios_strings.grd
@@ -1775,6 +1775,9 @@ <message name="IDS_IOS_TOOLS_MENU_REQUEST_MOBILE_SITE" desc="The iOS menu item for requesting the mobile site [iOS only]" meaning="Request the mobile version of the current web site. [Length: Unlimited]"> Request Mobile Site </message> + <message name="IDS_IOS_TOOLS_MENU_SEARCH_COPIED_IMAGE" desc="The iOS menu item for searching for the image copied to the system clipboard"> + Search Copied Image + </message> <message name="IDS_IOS_TOOLS_MENU_SEARCH_COPIED_TEXT" desc="The iOS menu item for pasting text in the omnibox and searching for the text."> Search Copied Text </message>
diff --git a/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_SEARCH_COPIED_IMAGE.png.sha1 b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_SEARCH_COPIED_IMAGE.png.sha1 new file mode 100644 index 0000000..0fa4a2f4 --- /dev/null +++ b/ios/chrome/app/strings/ios_strings_grd/IDS_IOS_TOOLS_MENU_SEARCH_COPIED_IMAGE.png.sha1
@@ -0,0 +1 @@ +e3362f58b1ce066591b4318ab118cfba6bfeda2a \ No newline at end of file
diff --git a/ios/chrome/browser/find_in_page/find_tab_helper.h b/ios/chrome/browser/find_in_page/find_tab_helper.h index 4c8aa98..1b7f9fb 100644 --- a/ios/chrome/browser/find_in_page/find_tab_helper.h +++ b/ios/chrome/browser/find_in_page/find_tab_helper.h
@@ -77,9 +77,8 @@ FindTabHelper(web::WebState* web_state); // web::WebStateObserver. - void NavigationItemCommitted( - web::WebState* web_state, - const web::LoadCommittedDetails& load_details) override; + void DidFinishNavigation(web::WebState* web_state, + web::NavigationContext* navigation_context) override; void WebStateDestroyed(web::WebState* web_state) override; // The ObjC find in page controller.
diff --git a/ios/chrome/browser/find_in_page/find_tab_helper.mm b/ios/chrome/browser/find_in_page/find_tab_helper.mm index c34c39d..ee34163 100644 --- a/ios/chrome/browser/find_in_page/find_tab_helper.mm +++ b/ios/chrome/browser/find_in_page/find_tab_helper.mm
@@ -85,9 +85,9 @@ [controller_ restoreSearchTerm]; } -void FindTabHelper::NavigationItemCommitted( +void FindTabHelper::DidFinishNavigation( web::WebState* web_state, - const web::LoadCommittedDetails& load_details) { + web::NavigationContext* navigation_context) { StopFinding(nil); }
diff --git a/ios/chrome/browser/search_engines/search_engines_util.cc b/ios/chrome/browser/search_engines/search_engines_util.cc index 7c47af1..70540dd 100644 --- a/ios/chrome/browser/search_engines/search_engines_util.cc +++ b/ios/chrome/browser/search_engines/search_engines_util.cc
@@ -112,4 +112,10 @@ new LoadedObserver(service); // The observer manages its own lifetime. } +bool SupportsSearchByImage(TemplateURLService* service) { + const TemplateURL* default_url = service->GetDefaultSearchProvider(); + return default_url && !default_url->image_url().empty() && + default_url->image_url_ref().IsValid(service->search_terms_data()); +} + } // namespace search_engines
diff --git a/ios/chrome/browser/search_engines/search_engines_util.h b/ios/chrome/browser/search_engines/search_engines_util.h index 69e36c1..2ecd221 100644 --- a/ios/chrome/browser/search_engines/search_engines_util.h +++ b/ios/chrome/browser/search_engines/search_engines_util.h
@@ -17,6 +17,10 @@ void UpdateSearchEnginesIfNeeded(PrefService* preferences, TemplateURLService* service); +// Checks whether the default url of the given template url supports searching +// by image. +bool SupportsSearchByImage(TemplateURLService* service); + } // namespace search_engines #endif // IOS_CHROME_BROWSER_SEARCH_ENGINES_SEARCH_ENGINES_UTIL_H_
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm index 5349a691..773f665 100644 --- a/ios/chrome/browser/ui/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -54,6 +54,7 @@ #import "ios/chrome/browser/prerender/prerender_service_factory.h" #include "ios/chrome/browser/reading_list/offline_url_utils.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" +#include "ios/chrome/browser/search_engines/search_engines_util.h" #include "ios/chrome/browser/search_engines/template_url_service_factory.h" #include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/signin/account_consistency_service_factory.h" @@ -105,6 +106,7 @@ #import "ios/chrome/browser/ui/fullscreen/fullscreen_ui_updater.h" #import "ios/chrome/browser/ui/image_util/image_copier.h" #import "ios/chrome/browser/ui/image_util/image_saver.h" +#import "ios/chrome/browser/ui/image_util/image_util.h" #import "ios/chrome/browser/ui/infobars/infobar_container_coordinator.h" #import "ios/chrome/browser/ui/infobars/infobar_positioner.h" #import "ios/chrome/browser/ui/key_commands_provider.h" @@ -193,6 +195,7 @@ #include "ios/web/public/web_client.h" #import "ios/web/public/web_state/context_menu_params.h" #import "ios/web/public/web_state/js/crw_js_injection_receiver.h" +#import "ios/web/public/web_state/navigation_context.h" #import "ios/web/public/web_state/ui/crw_native_content_provider.h" #import "ios/web/public/web_state/ui/crw_web_view_proxy.h" #import "ios/web/public/web_state/ui/crw_web_view_scroll_view_proxy.h" @@ -202,7 +205,6 @@ #include "ios/web/public/web_thread.h" #import "ios/web/web_state/ui/crw_web_controller.h" #include "services/network/public/cpp/shared_url_loader_factory.h" -#include "third_party/google_toolbox_for_mac/src/iPhone/GTMUIImage+Resize.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/page_transition_types.h" @@ -270,11 +272,6 @@ // Duration of the toolbar animation. const NSTimeInterval kLegacyFullscreenControllerToolbarAnimationDuration = 0.3; -// Dimensions to use when downsizing an image for search-by-image. -const CGFloat kSearchByImageMaxImageArea = 90000.0; -const CGFloat kSearchByImageMaxImageWidth = 600.0; -const CGFloat kSearchByImageMaxImageHeight = 400.0; - // When the tab strip moves beyond this origin offset, switch the status bar // appearance from light to dark. const CGFloat kTabStripAppearanceOffset = -29; @@ -3290,9 +3287,8 @@ TemplateURLService* service = ios::TemplateURLServiceFactory::GetForBrowserState(_browserState); - const TemplateURL* defaultURL = service->GetDefaultSearchProvider(); - if (defaultURL && !defaultURL->image_url().empty() && - defaultURL->image_url_ref().IsValid(service->search_terms_data())) { + if (search_engines::SupportsSearchByImage(service)) { + const TemplateURL* defaultURL = service->GetDefaultSearchProvider(); title = l10n_util::GetNSStringF(IDS_IOS_CONTEXT_MENU_SEARCHWEBFORIMAGE, defaultURL->short_name()); action = ^{ @@ -3360,27 +3356,25 @@ } } -// Performs a search using |data| and |imageURL| as inputs. +// Performs a search using |data| and |imageURL| as inputs. Opens the results in +// a new tab based on |inNewTab|. - (void)searchByImageData:(NSData*)data atURL:(const GURL&)imageURL { NSData* imageData = data; - UIImage* image = [UIImage imageWithData:imageData]; - // Downsize the image if its area exceeds kSearchByImageMaxImageArea AND - // (either its width exceeds kSearchByImageMaxImageWidth OR its height exceeds - // kSearchByImageMaxImageHeight). - if (image && - image.size.height * image.size.width > kSearchByImageMaxImageArea && - (image.size.width > kSearchByImageMaxImageWidth || - image.size.height > kSearchByImageMaxImageHeight)) { - CGSize newImageSize = - CGSizeMake(kSearchByImageMaxImageWidth, kSearchByImageMaxImageHeight); - image = [image gtm_imageByResizingToSize:newImageSize - preserveAspectRatio:YES - trimToFit:NO]; - imageData = UIImageJPEGRepresentation(image, 1.0); + UIImage* image = [UIImage imageWithData:data]; + UIImage* resizedImage = ResizeImageForSearchByImage(image); + if (![image isEqual:resizedImage]) { + imageData = UIImageJPEGRepresentation(resizedImage, 1.0); } + [self searchByResizedImageData:imageData atURL:&imageURL inNewTab:YES]; +} - char const* bytes = reinterpret_cast<const char*>([imageData bytes]); - std::string byteString(bytes, [imageData length]); +// Performs a search with the given image data. The data should alread have +// been scaled down in |ResizeImageForSearchByImage|. +- (void)searchByResizedImageData:(NSData*)data + atURL:(const GURL*)imageURL + inNewTab:(BOOL)inNewTab { + char const* bytes = reinterpret_cast<const char*>([data bytes]); + std::string byteString(bytes, [data length]); TemplateURLService* templateUrlService = ios::TemplateURLServiceFactory::GetForBrowserState(_browserState); @@ -3390,7 +3384,9 @@ DCHECK(defaultURL->image_url_ref().IsValid( templateUrlService->search_terms_data())); TemplateURLRef::SearchTermsArgs search_args(base::ASCIIToUTF16("")); - search_args.image_url = imageURL; + if (imageURL) { + search_args.image_url = *imageURL; + } search_args.image_thumbnail_content = byteString; // Generate the URL and populate |post_content| with the content type and @@ -3398,24 +3394,26 @@ TemplateURLRef::PostContent postContent; GURL result(defaultURL->image_url_ref().ReplaceSearchTerms( search_args, templateUrlService->search_terms_data(), &postContent)); - [self.tabModel - insertTabWithLoadParams:web_navigation_util::CreateWebLoadParams( - result, ui::PAGE_TRANSITION_TYPED, - &postContent) - opener:nil - openedByDOM:NO - atIndex:self.tabModel.count - inBackground:NO]; + web::NavigationManager::WebLoadParams loadParams = + web_navigation_util::CreateWebLoadParams( + result, ui::PAGE_TRANSITION_TYPED, &postContent); + if (inNewTab) { + [self.tabModel insertTabWithLoadParams:loadParams + opener:nil + openedByDOM:NO + atIndex:self.tabModel.count + inBackground:NO]; + } else { + [self loadURLWithParams:ChromeLoadParams(loadParams)]; + } } #pragma mark - CRWWebStateObserver methods. -// TODO(crbug.com/918934): didCommitNavigationWithDetails is deprecated, and -// this call to closeFindInPage incorrectly triggers for all navigations, not -// just navigations in the active WebState. +// TODO(crbug.com/918934): This call to closeFindInPage incorrectly triggers for +// all navigations, not just navigations in the active WebState. - (void)webState:(web::WebState*)webState - didCommitNavigationWithDetails: - (const web::LoadCommittedDetails&)load_details { + didFinishNavigation:(web::NavigationContext*)navigation { // Stop any Find in Page searches and close the find bar when navigating to a // new page. [self closeFindInPage]; @@ -4394,6 +4392,12 @@ [nativeController focusFakebox]; } +- (void)searchByImage:(UIImage*)image { + UIImage* resizedImage = ResizeImageForSearchByImage(image); + NSData* data = UIImageJPEGRepresentation(resizedImage, 1.0); + [self searchByResizedImageData:data atURL:nil inNewTab:NO]; +} + #pragma mark - BrowserCommands helpers // Reloads the original url of the last non-redirect item (including non-history
diff --git a/ios/chrome/browser/ui/commands/browser_commands.h b/ios/chrome/browser/ui/commands/browser_commands.h index 1315a9c..aec94190 100644 --- a/ios/chrome/browser/ui/commands/browser_commands.h +++ b/ios/chrome/browser/ui/commands/browser_commands.h
@@ -6,6 +6,7 @@ #define IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_ #import <Foundation/Foundation.h> +#import <UIKit/UIKit.h> #import "ios/chrome/browser/ui/commands/activity_service_commands.h" #import "ios/chrome/browser/ui/commands/browser_coordinator_commands.h" @@ -101,6 +102,9 @@ // omnibox. - (void)focusFakebox; +// Searches for an image in the current tab. +- (void)searchByImage:(UIImage*)image; + @end #endif // IOS_CHROME_BROWSER_UI_COMMANDS_BROWSER_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/image_util/BUILD.gn b/ios/chrome/browser/ui/image_util/BUILD.gn index 200b529..3fb922a 100644 --- a/ios/chrome/browser/ui/image_util/BUILD.gn +++ b/ios/chrome/browser/ui/image_util/BUILD.gn
@@ -21,6 +21,7 @@ "//ios/chrome/browser/web", "//ios/web", "//net", + "//third_party/google_toolbox_for_mac", "//ui/base", ] configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/chrome/browser/ui/image_util/image_util.h b/ios/chrome/browser/ui/image_util/image_util.h index 974d1de..f4a579e 100644 --- a/ios/chrome/browser/ui/image_util/image_util.h +++ b/ios/chrome/browser/ui/image_util/image_util.h
@@ -39,4 +39,9 @@ // is nil, empty, or cannot be recognized, nil will be returned. NSString* GetImageUTIFromData(NSData* data); +// Downsizes the image if its area exceeds kSearchByImageMaxImageArea AND +// (either its width exceeds kSearchByImageMaxImageWidth OR its height exceeds +// kSearchByImageMaxImageHeight) in preparation for searching. +UIImage* ResizeImageForSearchByImage(UIImage* image); + #endif // IOS_CHROME_BROWSER_UI_IMAGE_UTIL_IMAGE_UTIL_H_
diff --git a/ios/chrome/browser/ui/image_util/image_util.mm b/ios/chrome/browser/ui/image_util/image_util.mm index 521421b..05a7102 100644 --- a/ios/chrome/browser/ui/image_util/image_util.mm +++ b/ios/chrome/browser/ui/image_util/image_util.mm
@@ -7,6 +7,7 @@ #import "ios/chrome/browser/ui/image_util/image_util.h" +#include "third_party/google_toolbox_for_mac/src/iPhone/GTMUIImage+Resize.h" #include "ui/gfx/color_analysis.h" #include "ui/gfx/image/image.h" @@ -22,6 +23,11 @@ NSString* kImageExtensionGIF = @"gif"; NSString* kImageExtensionICO = @"ico"; NSString* kImageExtensionWebP = @"webp"; + +// Dimensions to use when downsizing an image for search-by-image. +const CGFloat kSearchByImageMaxImageArea = 90000.0; +const CGFloat kSearchByImageMaxImageWidth = 600.0; +const CGFloat kSearchByImageMaxImageHeight = 400.0; } UIColor* DominantColorForImage(const gfx::Image& image, CGFloat opacity) { @@ -107,3 +113,17 @@ }; return dict[GetImageExtensionFromData(data)]; } + +UIImage* ResizeImageForSearchByImage(UIImage* image) { + if (image && + image.size.height * image.size.width > kSearchByImageMaxImageArea && + (image.size.width > kSearchByImageMaxImageWidth || + image.size.height > kSearchByImageMaxImageHeight)) { + CGSize newImageSize = + CGSizeMake(kSearchByImageMaxImageWidth, kSearchByImageMaxImageHeight); + image = [image gtm_imageByResizingToSize:newImageSize + preserveAspectRatio:YES + trimToFit:NO]; + } + return image; +}
diff --git a/ios/chrome/browser/ui/popup_menu/BUILD.gn b/ios/chrome/browser/ui/popup_menu/BUILD.gn index 5a6460a..d22edf9 100644 --- a/ios/chrome/browser/ui/popup_menu/BUILD.gn +++ b/ios/chrome/browser/ui/popup_menu/BUILD.gn
@@ -49,6 +49,7 @@ "//ios/chrome/browser/feature_engagement", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/reading_list", + "//ios/chrome/browser/search_engines", "//ios/chrome/browser/ui", "//ios/chrome/browser/ui/activity_services", "//ios/chrome/browser/ui/bookmarks",
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm index a40114d49..01469037a 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_action_handler.mm
@@ -156,6 +156,17 @@ RecordAction(UserMetricsAction("MobileMenuScanQRCode")); [self.dispatcher showQRScanner]; break; + case PopupMenuActionSearchCopiedImage: { + DCHECK(base::FeatureList::IsEnabled(omnibox::kCopiedTextBehavior)); + RecordAction(UserMetricsAction("MobileMenuSearchCopiedImage")); + ClipboardRecentContent* clipboardRecentContent = + ClipboardRecentContent::GetInstance(); + if (base::Optional<gfx::Image> image = + clipboardRecentContent->GetRecentImageFromClipboard()) { + [self.dispatcher searchByImage:[image.value().ToUIImage() copy]]; + } + break; + } default: NOTREACHED() << "Unexpected identifier"; break;
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_constants.h b/ios/chrome/browser/ui/popup_menu/popup_menu_constants.h index ac7dc1e..afb30795 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_constants.h +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_constants.h
@@ -60,5 +60,7 @@ extern NSString* const kToolsMenuVoiceSearch; // QR Code Search item accessibility Identifier. extern NSString* const kToolsMenuQRCodeSearch; +// Copied Image Search item accessibility Identifier. +extern NSString* const kToolsMenuCopiedImageSearch; #endif // IOS_CHROME_BROWSER_UI_POPUP_MENU_POPUP_MENU_CONSTANTS_H_
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_constants.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_constants.mm index 91a1f7b..4a33b6f1 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_constants.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_constants.mm
@@ -38,3 +38,4 @@ NSString* const kToolsMenuPasteAndGo = @"kToolsMenuPasteAndGo"; NSString* const kToolsMenuVoiceSearch = @"kToolsMenuVoiceSearch"; NSString* const kToolsMenuQRCodeSearch = @"kToolsMenuQRCodeSearch"; +NSString* const kToolsMenuCopiedImageSearch = @"kToolsMenuCopiedImageSearch";
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm index 47eaba0..89e1dad 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_coordinator.mm
@@ -12,6 +12,7 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/feature_engagement/tracker_factory.h" #include "ios/chrome/browser/reading_list/reading_list_model_factory.h" +#import "ios/chrome/browser/search_engines/template_url_service_factory.h" #import "ios/chrome/browser/ui/bubble/bubble_presenter.h" #import "ios/chrome/browser/ui/bubble/bubble_view_controller_presenter.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" @@ -230,10 +231,12 @@ self.mediator.engagementTracker = feature_engagement::TrackerFactory::GetForBrowserState(self.browserState); self.mediator.webStateList = self.webStateList; - self.mediator.popupMenu = tableViewController; self.mediator.dispatcher = static_cast<id<BrowserCommands>>(self.dispatcher); self.mediator.bookmarkModel = ios::BookmarkModelFactory::GetForBrowserState(self.browserState); + self.mediator.templateURLService = + ios::TemplateURLServiceFactory::GetForBrowserState(self.browserState); + self.mediator.popupMenu = tableViewController; self.actionHandler = [[PopupMenuActionHandler alloc] init]; self.actionHandler.baseViewController = self.baseViewController;
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h index 01d7f183..f0ea9966 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.h
@@ -19,6 +19,7 @@ @protocol BrowserCommands; @protocol PopupMenuConsumer; class ReadingListModel; +class TemplateURLService; class WebStateList; // Mediator for the popup menu. This object is in charge of creating and @@ -48,6 +49,9 @@ @property(nonatomic, assign) feature_engagement::Tracker* engagementTracker; // The bookmarks model to know if the page is bookmarked. @property(nonatomic, assign) bookmarks::BookmarkModel* bookmarkModel; +// The template url service to use for checking whether search by image is +// available. +@property(nonatomic, assign) TemplateURLService* templateURLService; // Disconnect the mediator. - (void)disconnect;
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm index 6b88238..51065b5 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -12,8 +12,10 @@ #include "components/feature_engagement/public/tracker.h" #include "components/omnibox/browser/omnibox_field_trial.h" #include "components/open_from_clipboard/clipboard_recent_content.h" +#import "ios/chrome/browser/browser_state/chrome_browser_state.h" #include "ios/chrome/browser/chrome_url_constants.h" #import "ios/chrome/browser/find_in_page/find_tab_helper.h" +#import "ios/chrome/browser/search_engines/search_engines_util.h" #import "ios/chrome/browser/ui/activity_services/canonical_url_retriever.h" #include "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h" #import "ios/chrome/browser/ui/commands/browser_commands.h" @@ -590,18 +592,26 @@ if (base::FeatureList::IsEnabled(omnibox::kCopiedTextBehavior)) { ClipboardRecentContent* clipboardRecentContent = ClipboardRecentContent::GetInstance(); - NSNumber* titleID = nil; - if (clipboardRecentContent->GetRecentURLFromClipboard()) { - titleID = [NSNumber numberWithInt:IDS_IOS_TOOLS_MENU_VISIT_COPIED_LINK]; + PopupMenuToolsItem* copiedContentItem = nil; + + if (search_engines::SupportsSearchByImage(self.templateURLService) && + clipboardRecentContent->GetRecentImageFromClipboard()) { + copiedContentItem = CreateTableViewItem( + IDS_IOS_TOOLS_MENU_SEARCH_COPIED_IMAGE, + PopupMenuActionSearchCopiedImage, @"popup_menu_paste_and_go", + kToolsMenuCopiedImageSearch); + } else if (clipboardRecentContent->GetRecentURLFromClipboard()) { + copiedContentItem = CreateTableViewItem( + IDS_IOS_TOOLS_MENU_VISIT_COPIED_LINK, PopupMenuActionPasteAndGo, + @"popup_menu_paste_and_go", kToolsMenuPasteAndGo); } else if (clipboardRecentContent->GetRecentTextFromClipboard()) { - titleID = [NSNumber numberWithInt:IDS_IOS_TOOLS_MENU_SEARCH_COPIED_TEXT]; + copiedContentItem = CreateTableViewItem( + IDS_IOS_TOOLS_MENU_SEARCH_COPIED_TEXT, PopupMenuActionPasteAndGo, + @"popup_menu_paste_and_go", kToolsMenuPasteAndGo); } - if (titleID) { - PopupMenuToolsItem* pasteAndGo = - CreateTableViewItem(titleID.intValue, PopupMenuActionPasteAndGo, - @"popup_menu_paste_and_go", kToolsMenuPasteAndGo); - [items addObject:pasteAndGo]; + if (copiedContentItem) { + [items addObject:copiedContentItem]; } } else { NSString* pasteboardString = [UIPasteboard generalPasteboard].string;
diff --git a/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_item.h b/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_item.h index efbaf9c..18a1654 100644 --- a/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_item.h +++ b/ios/chrome/browser/ui/popup_menu/public/cells/popup_menu_item.h
@@ -34,6 +34,7 @@ PopupMenuActionPasteAndGo, PopupMenuActionVoiceSearch, PopupMenuActionQRCodeSearch, + PopupMenuActionSearchCopiedImage, }; // Protocol defining a popup item.
diff --git a/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h b/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h index 729fb5e..28cd217 100644 --- a/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h +++ b/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.h
@@ -59,9 +59,8 @@ bool user_action) override; // WebStateObserver: - void NavigationItemCommitted( - web::WebState* web_state, - const web::LoadCommittedDetails& load_details) override; + void DidFinishNavigation(web::WebState* web_state, + web::NavigationContext* navigation_context) override; void WebStateDestroyed(web::WebState* web_state) override; // Helper object that listens for TTS notifications.
diff --git a/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.mm b/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.mm index d3756f1e..2a8b710 100644 --- a/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.mm +++ b/ios/chrome/browser/ui/voice/text_to_speech_playback_controller.mm
@@ -108,9 +108,9 @@ #pragma mark WebStateObserver -void TextToSpeechPlaybackController::NavigationItemCommitted( +void TextToSpeechPlaybackController::DidFinishNavigation( web::WebState* web_state, - const web::LoadCommittedDetails& load_details) { + web::NavigationContext* navigation_context) { [notification_helper_ cancelPlayback]; }
diff --git a/ios/chrome/browser/voice/voice_search_navigations_tab_helper.h b/ios/chrome/browser/voice/voice_search_navigations_tab_helper.h index 79af113..aafe060 100644 --- a/ios/chrome/browser/voice/voice_search_navigations_tab_helper.h +++ b/ios/chrome/browser/voice/voice_search_navigations_tab_helper.h
@@ -29,9 +29,8 @@ explicit VoiceSearchNavigationTabHelper(web::WebState* web_state); // WebStateObserver: - void NavigationItemCommitted( - web::WebState* web_state, - const web::LoadCommittedDetails& load_details) override; + void DidFinishNavigation(web::WebState* web_state, + web::NavigationContext* navigation_context) override; void WebStateDestroyed(web::WebState* web_state) override; // The WebState this instance is observing. Will be null after
diff --git a/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm b/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm index 8a93b371..5d91c5471 100644 --- a/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm +++ b/ios/chrome/browser/voice/voice_search_navigations_tab_helper.mm
@@ -7,26 +7,13 @@ #include <memory> #include "base/logging.h" -#include "ios/web/public/load_committed_details.h" -#import "ios/web/public/navigation_item.h" -#import "ios/web/public/navigation_manager.h" +#import "ios/web/public/web_state/navigation_context.h" #import "ios/web/public/web_state/web_state.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." #endif -namespace { -// The key under which the VoiceSearchNavigationMarkers are stored. -const void* const kNavigationMarkerKey = &kNavigationMarkerKey; -} - -#pragma mark - VoiceSearchNavigationMarker - -// A marker object that can be added to a NavigationItem. Its presence -// indicates that the navigation is the result of a voice search query. -class VoiceSearchNavigationMarker : public base::SupportsUserData::Data {}; - #pragma mark - VoiceSearchNavigations VoiceSearchNavigationTabHelper::VoiceSearchNavigationTabHelper( @@ -43,13 +30,11 @@ return will_navigate_to_voice_search_result_; } -void VoiceSearchNavigationTabHelper::NavigationItemCommitted( +void VoiceSearchNavigationTabHelper::DidFinishNavigation( web::WebState* web_state, - const web::LoadCommittedDetails& load_details) { + web::NavigationContext* context) { DCHECK_EQ(web_state_, web_state); - if (will_navigate_to_voice_search_result_) { - web_state->GetNavigationManager()->GetLastCommittedItem()->SetUserData( - kNavigationMarkerKey, std::make_unique<VoiceSearchNavigationMarker>()); + if (will_navigate_to_voice_search_result_ && context->HasCommitted()) { will_navigate_to_voice_search_result_ = false; } }
diff --git a/ios/web/navigation/error_retry_state_machine.mm b/ios/web/navigation/error_retry_state_machine.mm index 3beaf057..02be34d 100644 --- a/ios/web/navigation/error_retry_state_machine.mm +++ b/ios/web/navigation/error_retry_state_machine.mm
@@ -147,6 +147,18 @@ return ErrorRetryCommand::kRewriteWebViewURL; } + if (wk_navigation_util::IsRestoreSessionUrl(web_view_url)) { + GURL target_url; + if (wk_navigation_util::ExtractTargetURL(web_view_url, &target_url) && + target_url == url_) { + // (10) Back/forward navigation to a restored session entry in offline + // mode. It is OK to consider this load succeeded for now because the + // failure delegate will be triggered again if the load fails. + state_ = ErrorRetryState::kNoNavigationError; + return ErrorRetryCommand::kDoNothing; + } + } + // (5) This is either a reload of the original URL that succeeded in // WebView (either because it was already in Page Cache or the network // load succeded), or a back/forward of a previous WebUI error that is
diff --git a/ios/web/navigation/error_retry_state_machine_unittest.mm b/ios/web/navigation/error_retry_state_machine_unittest.mm index 1143bf2e..64986998 100644 --- a/ios/web/navigation/error_retry_state_machine_unittest.mm +++ b/ios/web/navigation/error_retry_state_machine_unittest.mm
@@ -144,6 +144,17 @@ ASSERT_EQ(ErrorRetryState::kReadyToDisplayErrorForFailedNavigation, clone.state()); } + + // Simulate back/forward navigation to a restored session entry that never + // succeeded in loading. + { + const GURL restore_session_url = + wk_navigation_util::CreateRedirectUrl(test_url); + ErrorRetryStateMachine clone(machine); + ASSERT_EQ(ErrorRetryCommand::kDoNothing, + clone.DidFinishNavigation(restore_session_url)); + ASSERT_EQ(ErrorRetryState::kNoNavigationError, clone.state()); + } } // Tests load failure after navigation is committed.
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 57fcf41f4..41e534d 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -782,6 +782,9 @@ // used in the context of a URL KVO callback firing, and only if |isLoading| is // YES for the web view (since if it's not, no guesswork is needed). - (BOOL)isKVOChangePotentialSameDocumentNavigationToURL:(const GURL&)newURL; +// Returns YES if a SafeBrowsing warning is currently displayed within +// WKWebView. +- (BOOL)isSafeBrowsingWarningDisplayedInWebView; // Called when a non-document-changing URL change occurs. Updates the // _documentURL, and informs the superclass of the change. - (void)URLDidChangeWithoutDocumentChange:(const GURL&)URL; @@ -1082,6 +1085,27 @@ return !_webProcessCrashed && [_containerView isViewAlive]; } +- (BOOL)isSafeBrowsingWarningDisplayedInWebView { + // A SafeBrowsing warning is a UIScrollView that is inserted on top of + // WKWebView's scroll view. This method uses heuristics to detect this view. + // It may break in the future if WebKit's implementation of SafeBrowsing + // warnings changes. + UIView* containingView = _webView.scrollView.superview; + if (!containingView) + return NO; + + UIView* topView = containingView.subviews.lastObject; + + if (topView == _webView.scrollView) + return NO; + + return + [topView isKindOfClass:[UIScrollView class]] && + [NSStringFromClass([topView class]) containsString:@"Warning"] && + topView.subviews.count > 0 && + [topView.subviews[0].subviews.lastObject isKindOfClass:[UIButton class]]; +} + - (BOOL)contentIsHTML { if (!_webView) return NO; @@ -5288,25 +5312,35 @@ GURL webViewURL = net::GURLWithNSURL([_webView URL]); + if (![self isCurrentNavigationBackForward]) + return; + + web::NavigationContextImpl* existingContext = + [self contextForPendingMainFrameNavigationWithURL:webViewURL]; + // When traversing history restored from a previous session, WKWebView does // not fire 'pageshow', 'onload', 'popstate' or any of the // WKNavigationDelegate callbacks for back/forward navigation from an about: - // scheme placeholder URL to another entry. Loading state KVO is the only - // observable event in this scenario, so force a reload to trigger redirect - // from restore_session.html to the restored URL. + // scheme placeholder URL to another entry or if either of the redirect fails + // to load (e.g. in airplane mode). Loading state KVO is the only observable + // event in this scenario, so force a reload to trigger redirect from + // restore_session.html to the restored URL. bool previousURLHasAboutScheme = _documentURL.SchemeIs(url::kAboutScheme) || IsPlaceholderUrl(_documentURL) || web::GetWebClient()->IsAppSpecificURL(_documentURL); + bool is_back_forward_navigation = + existingContext && + (existingContext->GetPageTransition() & ui::PAGE_TRANSITION_FORWARD_BACK); if (web::GetWebClient()->IsSlimNavigationManagerEnabled() && - IsRestoreSessionUrl(webViewURL) && previousURLHasAboutScheme) { - [_webView reload]; - return; + IsRestoreSessionUrl(webViewURL)) { + if (previousURLHasAboutScheme || is_back_forward_navigation) { + [_webView reload]; + _loadPhase = web::LOAD_REQUESTED; + return; + } } - if (![self isCurrentNavigationBackForward]) - return; - // For failed navigations, WKWebView will sometimes revert to the previous URL // before committing the current navigation or resetting the web view's // |isLoading| property to NO. If this is the first navigation for the web @@ -5317,9 +5351,6 @@ return; } - web::NavigationContextImpl* existingContext = - [self contextForPendingMainFrameNavigationWithURL:webViewURL]; - if (!navigationWasCommitted && ![_pendingNavigationInfo cancelled]) { // A fast back-forward navigation does not call |didCommitNavigation:|, so // signal page change explicitly. @@ -5401,7 +5432,7 @@ return; } GURL URL(net::GURLWithNSURL([_webView URL])); - // URL changes happen at three points: + // URL changes happen at four points: // 1) When a load starts; at this point, the load is provisional, and // it should be ignored until it's committed, since the document/window // objects haven't changed yet. @@ -5410,11 +5441,15 @@ // be reported. // 3) When a navigation error occurs after provisional navigation starts, // the URL reverts to the previous URL without triggering a new navigation. + // 4) When a SafeBrowsing warning is displayed after + // decidePolicyForNavigationAction but before a provisional navigation + // starts, and the user clicks the "Go Back" link on the warning page. // - // If |isLoading| is NO, then it must be case 2 or 3. If the last committed - // URL (_documentURL) matches the current URL, assume that it is a revert from - // navigation failure and do nothing. If the URL does not match, assume it is - // a non-document-changing URL change, and handle accordingly. + // If |isLoading| is NO, then it must be case 2, 3, or 4. If the last + // committed URL (_documentURL) matches the current URL, assume that it is + // case 4 if a SafeBrowsing warning is currently displayed and case 3 + // otherwise. If the URL does not match, assume it is a non-document-changing + // URL change, and handle accordingly. // // If |isLoading| is YES, then it could either be case 1, or it could be case // 2 on a page that hasn't finished loading yet. If it's possible that it @@ -5428,8 +5463,31 @@ // window.location.href will match the previous URL at this stage, not the web // view's current URL. if (![_webView isLoading]) { - if (_documentURL == URL) + if (_documentURL == URL) { + if (![self isSafeBrowsingWarningDisplayedInWebView]) + return; + + self.navigationManagerImpl->DiscardNonCommittedItems(); + _webStateImpl->SetIsLoading(false); + _pendingNavigationInfo = nil; + if (web::GetWebClient()->IsSlimNavigationManagerEnabled()) { + // Right after a history navigation that gets cancelled by a tap on + // "Go Back", WKWebView's current back/forward list item will still be + // for the unsafe page; updating this is the responsibility of the + // WebProcess, so only happens after an IPC round-trip to and from the + // WebProcess with no notification to the embedder. This means that + // WKBasedNavigationManagerImpl::WKWebViewCache::GetCurrentItemIndex() + // will be the index of the unsafe page's item. To get back into a + // consistent state, force a reload. + [_webView reload]; + } else { + // Tapping "Go Back" on a SafeBrowsing interstitial can change whether + // there are any forward or back items, e.g., by returning to or + // moving away from the forward-most or back-most item. + _webStateImpl->OnBackForwardStateChanged(); + } return; + } // At this point, _webView, _webView.backForwardList.currentItem and its // associated NavigationItem should all have the same URL, except in two
diff --git a/ios/web/web_state/web_state_observer_inttest.mm b/ios/web/web_state/web_state_observer_inttest.mm index 6f3f943..16198da 100644 --- a/ios/web/web_state/web_state_observer_inttest.mm +++ b/ios/web/web_state/web_state_observer_inttest.mm
@@ -12,6 +12,7 @@ #import "base/test/ios/wait_util.h" #include "base/test/scoped_feature_list.h" #include "ios/testing/embedded_test_server_handlers.h" +#include "ios/web/navigation/wk_navigation_util.h" #import "ios/web/public/crw_navigation_item_storage.h" #import "ios/web/public/crw_session_storage.h" #include "ios/web/public/features.h" @@ -31,6 +32,7 @@ #import "ios/web/test/web_int_test.h" #import "ios/web/web_state/ui/crw_web_controller.h" #import "ios/web/web_state/web_state_impl.h" +#import "net/base/mac/url_conversions.h" #include "net/http/http_response_headers.h" #include "net/test/embedded_test_server/default_handlers.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -52,6 +54,8 @@ namespace { +using wk_navigation_util::CreateRedirectUrl; + const char kExpectedMimeType[] = "text/html"; const char kFailedTitle[] = "failed_title"; @@ -629,7 +633,7 @@ // A Google Mock matcher which matches |target_frame_is_main| member of // WebStatePolicyDecider::RequestInfo. This is needed because // WebStatePolicyDecider::RequestInfo doesn't support operator==. -MATCHER_P(RequestInfoMatch, expected_request_info, /* argument_name = */ "") { +MATCHER_P(RequestInfoMatch, expected_request_info, /*description=*/"") { return ui::PageTransitionTypeIncludingQualifiersIs( arg.transition_type, expected_request_info.transition_type) && arg.target_frame_is_main == @@ -637,6 +641,12 @@ arg.has_user_gesture == expected_request_info.has_user_gesture; } +// A GMock matcher that matches |URL| member of |arg| with |expected_url|. |arg| +// is expected to be either an NSURLRequest or NSURLResponse. +MATCHER_P(URLMatch, expected_url, /*description=*/"") { + return expected_url == net::GURLWithNSURL(arg.URL); +} + // Mocks WebStateObserver navigation callbacks. class WebStateObserverMock : public WebStateObserver { public: @@ -2154,6 +2164,9 @@ // Verifies that WebState::CreateWithStorageSession does not call any // WebStateObserver callbacks. +// TODO(crbug.com/738020): Remove this test after deprecating legacy navigation +// manager. Restore session in slim navigation manager is better tested in +// RestoreSessionOnline. TEST_P(WebStateObserverTest, RestoreSession) { // Create session storage. CRWNavigationItemStorage* item = [[CRWNavigationItemStorage alloc] init]; @@ -2205,6 +2218,116 @@ ASSERT_TRUE(test::WaitForPageToFinishLoading(web_state.get())); } +// Tests callbacks for restoring session and subsequently going back to +// about:blank. +TEST_P(WebStateObserverTest, RestoreSessionOnline) { + // LegacyNavigationManager doesn't trigger load in Restore. + if (!GetWebClient()->IsSlimNavigationManagerEnabled()) { + return; + } + + // Create a session of 3 items. Current item is at index 1. + const GURL url0("about:blank"); + auto item0 = std::make_unique<NavigationItemImpl>(); + item0->SetURL(url0); + + const GURL url1 = test_server_->GetURL("/echo?1"); + auto item1 = std::make_unique<NavigationItemImpl>(); + item1->SetURL(url1); + + const GURL url2 = test_server_->GetURL("/echo?2"); + auto item2 = std::make_unique<NavigationItemImpl>(); + item2->SetURL(url2); + + __block std::vector<std::unique_ptr<NavigationItem>> restored_items; + restored_items.push_back(std::move(item0)); + restored_items.push_back(std::move(item1)); + restored_items.push_back(std::move(item2)); + + // Initiate session restoration. + + EXPECT_CALL(*decider_, ShouldAllowRequest(_, _)).WillOnce(Return(true)); + EXPECT_CALL(*decider_, ShouldAllowResponse(_, /*for_main_frame=*/true)) + .WillOnce(Return(true)); + + // Back/forward state changes due to History API calls during session + // restoration. Called once each for CanGoBack and CanGoForward. + EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())).Times(2); + + // Client-side redirect to restore_session.html?targetUrl=url1. + EXPECT_CALL(*decider_, + ShouldAllowRequest(URLMatch(CreateRedirectUrl(url1)), _)) + .WillOnce(Return(true)); + EXPECT_CALL(*decider_, ShouldAllowResponse(URLMatch(CreateRedirectUrl(url1)), + /*for_main_frame=*/true)) + .WillOnce(Return(true)); + + // Client-side redirect to |url1|. + EXPECT_CALL(*decider_, ShouldAllowRequest(URLMatch(url1), _)) + .WillOnce(Return(true)); + EXPECT_CALL(observer_, DidStartLoading(web_state())); + EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); + EXPECT_CALL(*decider_, + ShouldAllowResponse(URLMatch(url1), /*for_main_frame=*/true)) + .WillOnce(Return(true)); + EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _)); + EXPECT_CALL(observer_, TitleWasSet(web_state())); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + EXPECT_CALL(observer_, + PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS)); + + ASSERT_TRUE(ExecuteBlockAndWaitForLoad(url1, ^{ + navigation_manager()->Restore(/*last_committed_item_index=*/1, + std::move(restored_items)); + })); + ASSERT_EQ(url1, navigation_manager()->GetLastCommittedItem()->GetURL()); + EXPECT_EQ(1, navigation_manager()->GetLastCommittedItemIndex()); + ASSERT_EQ(3, navigation_manager()->GetItemCount()); + ASSERT_TRUE(navigation_manager()->CanGoBack()); + ASSERT_TRUE(navigation_manager()->CanGoForward()); + + // Go back to |item0|. + + EXPECT_CALL(observer_, DidStartLoading(web_state())); + // Only CanGoBackward changes state on this navigation. + EXPECT_CALL(observer_, DidChangeBackForwardState(web_state())).Times(1); + + // Load restore_session.html?targetUrl=url0. + EXPECT_CALL(*decider_, + ShouldAllowRequest(URLMatch(CreateRedirectUrl(url0)), _)) + .WillOnce(Return(true)); + EXPECT_CALL(*decider_, ShouldAllowResponse(URLMatch(CreateRedirectUrl(url0)), + /*for_main_frame=*/true)) + .WillOnce(Return(true)); + + // decide policy for restore_session.html?targetUrl=url0 again due to reload + // in onpopstate(). + EXPECT_CALL(*decider_, + ShouldAllowRequest(URLMatch(CreateRedirectUrl(url0)), _)) + .WillOnce(Return(true)); + EXPECT_CALL(*decider_, ShouldAllowResponse(URLMatch(CreateRedirectUrl(url0)), + /*for_main_frame=*/true)) + .WillOnce(Return(true)); + + // Client-side redirect to |url0|. + EXPECT_CALL(*decider_, ShouldAllowRequest(URLMatch(url0), _)) + .WillOnce(Return(true)); + EXPECT_CALL(observer_, DidStartNavigation(web_state(), _)); + // No ShouldAllowResponse call because about:blank has no response. + EXPECT_CALL(observer_, DidFinishNavigation(web_state(), _)); + EXPECT_CALL(observer_, DidStopLoading(web_state())); + EXPECT_CALL(observer_, + PageLoaded(web_state(), PageLoadCompletionStatus::SUCCESS)); + + ASSERT_TRUE(ExecuteBlockAndWaitForLoad(url0, ^{ + navigation_manager()->GoBack(); + })); + ASSERT_EQ(url0, navigation_manager()->GetLastCommittedItem()->GetURL()); + EXPECT_EQ(0, navigation_manager()->GetLastCommittedItemIndex()); + ASSERT_TRUE(navigation_manager()->CanGoForward()); + ASSERT_FALSE(navigation_manager()->CanGoBack()); +} + INSTANTIATE_TEST_CASE_P( ProgrammaticWebStateObserverTest, WebStateObserverTest,
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc index d338d7d..3aa9e4d 100644 --- a/media/gpu/video_decode_accelerator_unittest.cc +++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -1700,16 +1700,21 @@ public: VDATestSuite(int argc, char** argv) : base::TestSuite(argc, argv) {} - int Run() { + private: + void Initialize() override { + base::TestSuite::Initialize(); + #if defined(OS_WIN) || defined(OS_CHROMEOS) // For windows the decoding thread initializes the media foundation decoder // which uses COM. We need the thread to be a UI thread. // On Ozone, the backend initializes the event system using a UI // thread. - base::test::ScopedTaskEnvironment scoped_task_environment( - base::test::ScopedTaskEnvironment::MainThreadType::UI); + scoped_task_environment_ = + std::make_unique<base::test::ScopedTaskEnvironment>( + base::test::ScopedTaskEnvironment::MainThreadType::UI); #else - base::test::ScopedTaskEnvironment scoped_task_environment; + scoped_task_environment_ = + std::make_unique<base::test::ScopedTaskEnvironment>(); #endif // OS_WIN || OS_CHROMEOS media::g_env = @@ -1729,8 +1734,14 @@ #elif defined(OS_WIN) media::DXVAVideoDecodeAccelerator::PreSandboxInitialization(); #endif - return base::TestSuite::Run(); } + + void Shutdown() override { + scoped_task_environment_.reset(); + base::TestSuite::Shutdown(); + } + + std::unique_ptr<base::test::ScopedTaskEnvironment> scoped_task_environment_; }; } // namespace
diff --git a/net/disk_cache/simple/simple_entry_impl.cc b/net/disk_cache/simple/simple_entry_impl.cc index e5096b4..ec225b0f 100644 --- a/net/disk_cache/simple/simple_entry_impl.cc +++ b/net/disk_cache/simple/simple_entry_impl.cc
@@ -16,6 +16,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/single_thread_task_runner.h" +#include "base/stl_util.h" #include "base/task_runner.h" #include "base/task_runner_util.h" #include "base/threading/thread_task_runner_handle.h" @@ -166,13 +167,17 @@ net::NetLogSourceType::DISK_CACHE_ENTRY)), stream_0_data_(base::MakeRefCounted<net::GrowableIOBuffer>()), entry_priority_(entry_priority) { - static_assert(arraysize(data_size_) == arraysize(crc32s_end_offset_), + static_assert(std::extent<decltype(data_size_)>() == + std::extent<decltype(crc32s_end_offset_)>(), "arrays should be the same size"); - static_assert(arraysize(data_size_) == arraysize(crc32s_), + static_assert( + std::extent<decltype(data_size_)>() == std::extent<decltype(crc32s_)>(), + "arrays should be the same size"); + static_assert(std::extent<decltype(data_size_)>() == + std::extent<decltype(have_written_)>(), "arrays should be the same size"); - static_assert(arraysize(data_size_) == arraysize(have_written_), - "arrays should be the same size"); - static_assert(arraysize(data_size_) == arraysize(crc_check_state_), + static_assert(std::extent<decltype(data_size_)>() == + std::extent<decltype(crc_check_state_)>(), "arrays should be the same size"); ResetEntry(); net_log_.BeginEvent(net::NetLogEventType::SIMPLE_CACHE_ENTRY, @@ -614,7 +619,7 @@ std::memset(crc32s_, 0, sizeof(crc32s_)); std::memset(have_written_, 0, sizeof(have_written_)); std::memset(data_size_, 0, sizeof(data_size_)); - for (size_t i = 0; i < arraysize(crc_check_state_); ++i) { + for (size_t i = 0; i < base::size(crc_check_state_); ++i) { crc_check_state_[i] = CRC_CHECK_NEVER_READ_AT_ALL; } }
diff --git a/net/dns/dns_config_service_posix.cc b/net/dns/dns_config_service_posix.cc index c51a632..31c564fa 100644 --- a/net/dns/dns_config_service_posix.cc +++ b/net/dns/dns_config_service_posix.cc
@@ -6,6 +6,7 @@ #include <memory> #include <string> +#include <type_traits> #include "base/bind.h" #include "base/files/file.h" @@ -465,8 +466,8 @@ dns_config->nameservers.push_back(ipe); } #elif defined(OS_LINUX) - static_assert(arraysize(res.nsaddr_list) >= MAXNS && - arraysize(res._u._ext.nsaddrs) >= MAXNS, + static_assert(std::extent<decltype(res.nsaddr_list)>() >= MAXNS && + std::extent<decltype(res._u._ext.nsaddrs)>() >= MAXNS, "incompatible libresolv res_state"); DCHECK_LE(res.nscount, MAXNS); // Initially, glibc stores IPv6 in |_ext.nsaddrs| and IPv4 in |nsaddr_list|.
diff --git a/net/third_party/quic/test_tools/quic_stream_id_manager_peer.h b/net/third_party/quic/test_tools/quic_stream_id_manager_peer.h index 9888cb4..2ceec2a 100644 --- a/net/third_party/quic/test_tools/quic_stream_id_manager_peer.h +++ b/net/third_party/quic/test_tools/quic_stream_id_manager_peer.h
@@ -4,7 +4,7 @@ #ifndef NET_THIRD_PARTY_QUIC_TEST_TOOLS_QUIC_STREAM_ID_MANAGER_PEER_H_ #define NET_THIRD_PARTY_QUIC_TEST_TOOLS_QUIC_STREAM_ID_MANAGER_PEER_H_ -#include "base/macros.h" +#include <stddef.h> namespace quic {
diff --git a/net/traffic_annotation/network_traffic_annotation.h b/net/traffic_annotation/network_traffic_annotation.h index 796bc038..4a67c9b 100644 --- a/net/traffic_annotation/network_traffic_annotation.h +++ b/net/traffic_annotation/network_traffic_annotation.h
@@ -153,7 +153,7 @@ const char (&proto)[N3]) { #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON) DCHECK(partial_annotation.completing_id_hash_code == - COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(unique_id) || + COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH(group_id) || partial_annotation.unique_id_hash_code == COMPUTE_NETWORK_TRAFFIC_ANNOTATION_ID_HASH("test_partial") || partial_annotation.unique_id_hash_code ==
diff --git a/services/media_session/audio_focus_manager.cc b/services/media_session/audio_focus_manager.cc index c775811..85e95e74 100644 --- a/services/media_session/audio_focus_manager.cc +++ b/services/media_session/audio_focus_manager.cc
@@ -17,6 +17,16 @@ namespace media_session { +namespace { + +mojom::EnforcementMode GetDefaultEnforcementMode() { + if (IsAudioFocusEnabled() && IsAudioFocusEnforcementEnabled()) + return mojom::EnforcementMode::kSingleGroup; + return mojom::EnforcementMode::kNone; +} + +} // namespace + class AudioFocusManager::StackRow : public mojom::AudioFocusRequestClient { public: StackRow(AudioFocusManager* owner, @@ -128,6 +138,22 @@ controller_->BindToInterface(std::move(request)); } + void Suspend(bool transient) { + DCHECK(!session_info_->force_duck); + transient_suspend_ = transient_suspend_ || transient; + session_->Suspend(mojom::MediaSession::SuspendType::kSystem); + } + + void MaybeResume() { + DCHECK(!session_info_->force_duck); + + if (!transient_suspend_) + return; + + transient_suspend_ = false; + session_->Resume(mojom::MediaSession::SuspendType::kSystem); + } + private: void SetSessionInfo(mojom::MediaSessionInfoPtr session_info) { bool is_controllable_changed = @@ -162,6 +188,7 @@ AudioFocusManagerMetricsHelper metrics_helper_; bool encountered_error_ = false; + bool transient_suspend_ = false; std::unique_ptr<MediaController> controller_; @@ -261,9 +288,7 @@ return; } - if (IsAudioFocusEnforcementEnabled()) - EnforceAudioFocusAbandon(row->audio_focus_type()); - + EnforceAudioFocusAbandon(); MaybeUpdateActiveSession(); // Notify observers that we lost audio focus. @@ -288,6 +313,21 @@ bindings_.dispatch_context()->source_name = name; } +void AudioFocusManager::SetEnforcementMode(mojom::EnforcementMode mode) { + if (mode == mojom::EnforcementMode::kDefault) + mode = GetDefaultEnforcementMode(); + + if (mode == enforcement_mode_) + return; + + enforcement_mode_ = mode; + + if (audio_focus_stack_.empty()) + return; + + EnforceAudioFocus(); +} + void AudioFocusManager::CreateActiveMediaController( mojom::MediaControllerRequest request) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); @@ -329,16 +369,10 @@ std::unique_ptr<StackRow> row, mojom::AudioFocusType type, base::OnceCallback<void()> callback) { - // If audio focus is enabled then we should enforce this request and make sure - // the new active session is not ducking. - if (IsAudioFocusEnforcementEnabled()) { - EnforceAudioFocusRequest(type, row->group_id()); - row->session()->StopDucking(); - } - row->SetAudioFocusType(type); audio_focus_stack_.push_back(std::move(row)); + EnforceAudioFocus(); MaybeUpdateActiveSession(); // Notify observers that we were gained audio focus. @@ -353,87 +387,49 @@ std::move(callback).Run(); } -void AudioFocusManager::EnforceAudioFocusRequest( - mojom::AudioFocusType type, - const base::UnguessableToken& group_id) { - DCHECK(IsAudioFocusEnforcementEnabled()); - - for (auto& old_session : audio_focus_stack_) { - // If the session has the force duck flag set then we should always duck it. - if (old_session->info()->force_duck) { - old_session->session()->StartDucking(); - continue; - } - - switch (type) { - case mojom::AudioFocusType::kGain: - case mojom::AudioFocusType::kGainTransient: - // If the session has the same group id as the new session then we - // should not suspend that session. - if (old_session->group_id() == group_id) - break; - - old_session->session()->Suspend( - mojom::MediaSession::SuspendType::kSystem); - break; - case mojom::AudioFocusType::kGainTransientMayDuck: - old_session->session()->StartDucking(); - break; - } - } -} - -void AudioFocusManager::EnforceAudioFocusAbandon(mojom::AudioFocusType type) { - DCHECK(IsAudioFocusEnforcementEnabled()); - +void AudioFocusManager::EnforceAudioFocusAbandon() { // Allow the top-most MediaSession having force duck to unduck even if // it is not active. - for (auto iter = audio_focus_stack_.rbegin(); - iter != audio_focus_stack_.rend(); ++iter) { - if (!(*iter)->info()->force_duck) - continue; + if (enforcement_mode_ != mojom::EnforcementMode::kNone) { + for (auto iter = audio_focus_stack_.rbegin(); + iter != audio_focus_stack_.rend(); ++iter) { + if (!(*iter)->info()->force_duck) + continue; - // TODO(beccahughes): Replace with std::rotate. - auto duck_row = std::move(*iter); - duck_row->session()->StopDucking(); - audio_focus_stack_.erase(std::next(iter).base()); - audio_focus_stack_.push_back(std::move(duck_row)); - return; + // TODO(beccahughes): Replace with std::rotate. + auto duck_row = std::move(*iter); + duck_row->session()->StopDucking(); + audio_focus_stack_.erase(std::next(iter).base()); + audio_focus_stack_.push_back(std::move(duck_row)); + return; + } } - DCHECK(!audio_focus_stack_.empty()); - StackRow* top = audio_focus_stack_.back().get(); + EnforceAudioFocus(); +} - switch (type) { - case mojom::AudioFocusType::kGain: - // Do nothing. The abandoned session suspended all the media sessions and - // they should stay suspended to avoid surprising the user. - break; - case mojom::AudioFocusType::kGainTransient: - // The abandoned session suspended all the media sessions but we should - // start playing the top one again as the abandoned media was transient. - // This will also apply to any sessions that have the same group_id as the - // new top most session. - for (auto& session : audio_focus_stack_) { - if (session->group_id() != top->group_id()) - continue; +void AudioFocusManager::EnforceAudioFocus() { + DCHECK_NE(mojom::EnforcementMode::kDefault, enforcement_mode_); + if (audio_focus_stack_.empty()) + return; - session->session()->Resume(mojom::MediaSession::SuspendType::kSystem); - } - break; - case mojom::AudioFocusType::kGainTransientMayDuck: - // The abandoned session ducked all the media sessions so we should unduck - // them. If they are not playing then they will not resume. - for (auto& session : base::Reversed(audio_focus_stack_)) { - session->session()->StopDucking(); + EnforcementState state; - // If the new session is ducking then we should continue ducking all but - // the new session. - if (top->audio_focus_type() == - mojom::AudioFocusType::kGainTransientMayDuck) - break; - } - break; + for (auto& session : base::Reversed(audio_focus_stack_)) { + EnforceSingleSession(session.get(), state); + + // Update the flags based on the audio focus type of this session. + switch (session->audio_focus_type()) { + case mojom::AudioFocusType::kGain: + state.should_suspend = true; + break; + case mojom::AudioFocusType::kGainTransient: + state.should_transient_suspend = true; + break; + case mojom::AudioFocusType::kGainTransientMayDuck: + state.should_duck = true; + break; + } } } @@ -462,7 +458,8 @@ }); } -AudioFocusManager::AudioFocusManager() { +AudioFocusManager::AudioFocusManager() + : enforcement_mode_(GetDefaultEnforcementMode()) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); } @@ -496,4 +493,60 @@ audio_focus_stack_.back()->audio_focus_type() == type; } +bool AudioFocusManager::ShouldSessionBeSuspended( + const StackRow* session, + const EnforcementState& state) const { + bool should_suspend_any = + state.should_suspend || state.should_transient_suspend; + + switch (enforcement_mode_) { + case mojom::EnforcementMode::kSingleSession: + return should_suspend_any; + case mojom::EnforcementMode::kSingleGroup: + return should_suspend_any && + session->group_id() != audio_focus_stack_.back()->group_id(); + case mojom::EnforcementMode::kNone: + return false; + case mojom::EnforcementMode::kDefault: + NOTIMPLEMENTED(); + return false; + } +} + +bool AudioFocusManager::ShouldSessionBeDucked( + const StackRow* session, + const EnforcementState& state) const { + switch (enforcement_mode_) { + case mojom::EnforcementMode::kSingleSession: + case mojom::EnforcementMode::kSingleGroup: + if (session->info()->force_duck) + return state.should_duck || ShouldSessionBeSuspended(session, state); + return state.should_duck; + case mojom::EnforcementMode::kNone: + return false; + case mojom::EnforcementMode::kDefault: + NOTIMPLEMENTED(); + return false; + } +} + +void AudioFocusManager::EnforceSingleSession(StackRow* session, + const EnforcementState& state) { + if (ShouldSessionBeDucked(session, state)) { + session->session()->StartDucking(); + } else { + session->session()->StopDucking(); + } + + // If the session wants to be ducked instead of suspended we should stop now. + if (session->info()->force_duck) + return; + + if (ShouldSessionBeSuspended(session, state)) { + session->Suspend(state.should_transient_suspend); + } else { + session->MaybeResume(); + } +} + } // namespace media_session
diff --git a/services/media_session/audio_focus_manager.h b/services/media_session/audio_focus_manager.h index 810f5fd..04cbfed 100644 --- a/services/media_session/audio_focus_manager.h +++ b/services/media_session/audio_focus_manager.h
@@ -55,6 +55,7 @@ void GetFocusRequests(GetFocusRequestsCallback callback) override; void AddObserver(mojom::AudioFocusObserverPtr observer) override; void SetSourceName(const std::string& name) override; + void SetEnforcementMode(mojom::EnforcementMode mode) override; // mojom::AudioFocusManagerDebug. void GetDebugInfoForRequest(const RequestId& request_id, @@ -95,14 +96,19 @@ std::string source_name; }; + struct EnforcementState { + bool should_duck = false; + bool should_suspend = false; + bool should_transient_suspend = false; + }; + void RequestAudioFocusInternal(std::unique_ptr<StackRow>, mojom::AudioFocusType, base::OnceCallback<void()>); - void EnforceAudioFocusRequest(mojom::AudioFocusType type, - const base::UnguessableToken& group_id); - void AbandonAudioFocusInternal(RequestId); - void EnforceAudioFocusAbandon(mojom::AudioFocusType); + + void EnforceAudioFocusAbandon(); + void EnforceAudioFocus(); void MaybeUpdateActiveSession(); @@ -115,6 +121,13 @@ bool IsSessionOnTopOfAudioFocusStack(RequestId id, mojom::AudioFocusType type) const; + bool ShouldSessionBeSuspended(const StackRow* session, + const EnforcementState& state) const; + bool ShouldSessionBeDucked(const StackRow* session, + const EnforcementState& state) const; + + void EnforceSingleSession(StackRow* session, const EnforcementState& state); + // This |MediaController| acts as a proxy for controlling the active // |MediaSession| over mojo. MediaController active_media_controller_; @@ -137,6 +150,8 @@ // A MediaSession must abandon audio focus before its destruction. std::list<std::unique_ptr<StackRow>> audio_focus_stack_; + mojom::EnforcementMode enforcement_mode_; + // Adding observers should happen on the same thread that the service is // running on. THREAD_CHECKER(thread_checker_);
diff --git a/services/media_session/audio_focus_manager_unittest.cc b/services/media_session/audio_focus_manager_unittest.cc index 1ea3fc4..bae9edd 100644 --- a/services/media_session/audio_focus_manager_unittest.cc +++ b/services/media_session/audio_focus_manager_unittest.cc
@@ -9,7 +9,6 @@ #include <vector> #include "base/callback.h" -#include "base/command_line.h" #include "base/run_loop.h" #include "base/test/metrics/histogram_tester.h" #include "base/test/scoped_command_line.h" @@ -18,7 +17,6 @@ #include "mojo/public/cpp/bindings/interface_request.h" #include "services/media_session/audio_focus_manager_metrics_helper.h" #include "services/media_session/media_session_service.h" -#include "services/media_session/public/cpp/switches.h" #include "services/media_session/public/cpp/test/audio_focus_test_util.h" #include "services/media_session/public/cpp/test/mock_media_session.h" #include "services/media_session/public/mojom/audio_focus.mojom.h" @@ -38,18 +36,12 @@ // This tests the Audio Focus Manager API. The parameter determines whether // audio focus is enabled or not. If it is not enabled it should track the media // sessions but not enforce single session focus. -class AudioFocusManagerTest : public testing::TestWithParam<bool> { +class AudioFocusManagerTest + : public testing::TestWithParam<mojom::EnforcementMode> { public: AudioFocusManagerTest() = default; void SetUp() override { - if (!GetParam()) { - command_line_.GetProcessCommandLine()->AppendSwitchASCII( - switches::kEnableAudioFocus, switches::kEnableAudioFocusNoEnforce); - } - - ASSERT_EQ(GetParam(), IsAudioFocusEnforcementEnabled()); - // Create an instance of the MediaSessionService. service_ = std::make_unique<MediaSessionService>( connector_factory_.RegisterInstance(mojom::kServiceName)); @@ -57,6 +49,9 @@ &audio_focus_ptr_); connector_factory_.GetDefaultConnector()->BindInterface( mojom::kServiceName, &audio_focus_debug_ptr_); + + audio_focus_ptr_->SetEnforcementMode(GetParam()); + audio_focus_ptr_.FlushForTesting(); } void TearDown() override { @@ -126,7 +121,7 @@ test::MockMediaSession* session) { mojom::MediaSessionInfo::SessionState state = session->GetState(); - if (!GetParam()) { + if (!IsEnforcementEnabled()) { // If audio focus enforcement is disabled then we should never see these // states in the tests. EXPECT_NE(mojom::MediaSessionInfo::SessionState::kSuspended, state); @@ -152,7 +147,7 @@ mojom::MediaSessionInfo::SessionState state) { // If enforcement is enabled then returns the provided state, otherwise // returns kActive because without enforcement we did not change state. - if (GetParam()) + if (IsEnforcementEnabled()) return state; return mojom::MediaSessionInfo::SessionState::kActive; } @@ -186,6 +181,15 @@ .size(); } + bool IsEnforcementEnabled() const { + return GetParam() == mojom::EnforcementMode::kSingleSession || + GetParam() == mojom::EnforcementMode::kSingleGroup; + } + + bool IsGroupingEnabled() const { + return GetParam() != mojom::EnforcementMode::kSingleSession; + } + private: int GetCountForType(mojom::AudioFocusType type) { const auto audio_focus_requests = GetRequests(); @@ -220,7 +224,7 @@ } void FlushForTestingIfEnabled() { - if (!GetParam()) + if (!IsEnforcementEnabled()) return; audio_focus_ptr_.FlushForTesting(); @@ -239,7 +243,13 @@ DISALLOW_COPY_AND_ASSIGN(AudioFocusManagerTest); }; -INSTANTIATE_TEST_CASE_P(, AudioFocusManagerTest, testing::Bool()); +INSTANTIATE_TEST_CASE_P( + , + AudioFocusManagerTest, + testing::Values(mojom::EnforcementMode::kDefault, + mojom::EnforcementMode::kNone, + mojom::EnforcementMode::kSingleGroup, + mojom::EnforcementMode::kSingleSession)); TEST_P(AudioFocusManagerTest, RequestAudioFocusGain_ReplaceFocusedEntry) { test::MockMediaSession media_session_1; @@ -683,7 +693,8 @@ GetState(&media_session_1)); media_session_3.AbandonAudioFocusFromClient(); - EXPECT_EQ(GetParam() ? request_id_1 : request_id_2, GetAudioFocusedSession()); + EXPECT_EQ(IsEnforcementEnabled() ? request_id_1 : request_id_2, + GetAudioFocusedSession()); } TEST_P(AudioFocusManagerTest, AudioFocusObserver_RequestNoop) { @@ -1105,7 +1116,9 @@ media_session_4.AbandonAudioFocusFromClient(); - EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + EXPECT_EQ(IsGroupingEnabled() + ? mojom::MediaSessionInfo::SessionState::kActive + : mojom::MediaSessionInfo::SessionState::kSuspended, GetState(&media_session_1)); EXPECT_EQ( GetStateFromParam(mojom::MediaSessionInfo::SessionState::kSuspended), @@ -1127,7 +1140,9 @@ RequestGroupedAudioFocus(&media_session_2, mojom::AudioFocusType::kGain, group_id); - EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + EXPECT_EQ(IsGroupingEnabled() + ? mojom::MediaSessionInfo::SessionState::kActive + : mojom::MediaSessionInfo::SessionState::kSuspended, GetState(&media_session_1)); EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, GetState(&media_session_2)); @@ -1163,13 +1178,12 @@ RequestGroupedAudioFocus(&media_session_2, mojom::AudioFocusType::kGainTransient, group_id); - EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, + EXPECT_EQ(IsGroupingEnabled() + ? mojom::MediaSessionInfo::SessionState::kActive + : mojom::MediaSessionInfo::SessionState::kSuspended, GetState(&media_session_1)); EXPECT_EQ(mojom::MediaSessionInfo::SessionState::kActive, GetState(&media_session_2)); } -// TODO: Fix //content -// TODO: Fix //ash - } // namespace media_session
diff --git a/services/media_session/media_controller_unittest.cc b/services/media_session/media_controller_unittest.cc index c92e5c9..16a15db8 100644 --- a/services/media_session/media_controller_unittest.cc +++ b/services/media_session/media_controller_unittest.cc
@@ -38,6 +38,10 @@ controller_manager_ptr_->CreateActiveMediaController( mojo::MakeRequest(&media_controller_ptr_)); controller_manager_ptr_.FlushForTesting(); + + audio_focus_ptr_->SetEnforcementMode( + mojom::EnforcementMode::kSingleSession); + audio_focus_ptr_.FlushForTesting(); } void TearDown() override {
diff --git a/services/media_session/public/mojom/audio_focus.mojom b/services/media_session/public/mojom/audio_focus.mojom index ead6a4c4..8c64774 100644 --- a/services/media_session/public/mojom/audio_focus.mojom +++ b/services/media_session/public/mojom/audio_focus.mojom
@@ -7,7 +7,29 @@ import "mojo/public/mojom/base/unguessable_token.mojom"; import "services/media_session/public/mojom/media_session.mojom"; -// Next MinVersion: 5 +// Next MinVersion: 6 + +// These are the different modes the AudioFocusManager can enforce audio focus. +[Extensible] +enum EnforcementMode { + // This will default to whatever enforcement mode is configured through + // feature flags. + kDefault, + + // This will allow all sessions to play, without the enforcement of a single + // media session. + kNone, + + // This will enforce that all media sessions playing have the same audio + // focus group id. If a session gains focus then all other sessions with + // a different group id will be ducked/paused. Any session with the same + // group id will be ignored. + kSingleGroup, + + // This will enforce that only one media session can be playing at any + // one time. + kSingleSession, +}; // These are the different types of audio focus that can be requested. [Extensible] @@ -72,7 +94,7 @@ }; // Controls audio focus across the entire system. -// Next Method ID: 5 +// Next Method ID: 6 interface AudioFocusManager { // Requests audio focus with |type| for the |media_session| with // |session_info|. Media sessions should provide a |request| that will @@ -105,6 +127,9 @@ // associating metrics to a source. If the source name is updated then // the audio focus requests will retain the previous source name. [MinVersion=2] SetSourceName@3(string name); + + // Sets the enforcement mode for the Audio Focus Manager. + [MinVersion=5] SetEnforcementMode@5(EnforcementMode mode); }; // Provides debug information about audio focus requests.
diff --git a/services/network/cross_origin_read_blocking.cc b/services/network/cross_origin_read_blocking.cc index ee5f6e69e..25e6bf9b 100644 --- a/services/network/cross_origin_read_blocking.cc +++ b/services/network/cross_origin_read_blocking.cc
@@ -565,11 +565,11 @@ CrossOriginReadBlocking::ResponseAnalyzer::ResponseAnalyzer( const net::URLRequest& request, const ResourceResponse& response, - InitiatorLockCompatibility initiator_compatibility) { + base::Optional<url::Origin> request_initiator_site_lock) { content_length_ = response.head.content_length; http_response_code_ = response.head.headers ? response.head.headers->response_code() : 0; - initiator_compatibility_ = initiator_compatibility; + request_initiator_site_lock_ = request_initiator_site_lock; should_block_based_on_headers_ = ShouldBlockBasedOnHeaders(request, response); if (should_block_based_on_headers_ == kNeedToSniffMore) @@ -587,9 +587,20 @@ // that are inexpensive should be near the top. url::Origin target_origin = url::Origin::Create(request.url()); + // Check if |target_origin| seems to match the factory lock in + // |request_initiator_site_lock_|. If so, then treat this request as + // same-origin (even if |request.initiator()| might be cross-origin). See + // also https://crbug.com/918660. + if (VerifyRequestInitiatorLock(request_initiator_site_lock_, target_origin) == + InitiatorLockCompatibility::kCompatibleLock) { + return kAllow; + } + // Treat a missing initiator as an empty origin to be safe, though we don't // expect this to happen. Unfortunately, this requires a copy. url::Origin initiator; + initiator_compatibility_ = VerifyRequestInitiatorLock( + request_initiator_site_lock_, request.initiator()); bool block_untrustworthy_initiator = ShouldEnforceInitiatorLock() && initiator_compatibility_ == InitiatorLockCompatibility::kIncorrectLock;
diff --git a/services/network/cross_origin_read_blocking.h b/services/network/cross_origin_read_blocking.h index 5103b17..6caca3c 100644 --- a/services/network/cross_origin_read_blocking.h +++ b/services/network/cross_origin_read_blocking.h
@@ -69,7 +69,7 @@ // ResponseAnalyzer will decide whether |response| needs to be blocked. ResponseAnalyzer(const net::URLRequest& request, const ResourceResponse& response, - InitiatorLockCompatibility initiator_compatibility); + base::Optional<url::Origin> request_initiator_site_lock); ~ResponseAnalyzer(); @@ -163,6 +163,9 @@ InitiatorLockCompatibility initiator_compatibility_ = InitiatorLockCompatibility::kIncorrectLock; + // Propagated from URLLoaderFactoryParams::request_initiator_site_lock; + base::Optional<url::Origin> request_initiator_site_lock_; + // The sniffers to be used. std::vector<std::unique_ptr<ConfirmationSniffer>> sniffers_;
diff --git a/services/network/initiator_lock_compatibility.cc b/services/network/initiator_lock_compatibility.cc index a352cad..7ca032b 100644 --- a/services/network/initiator_lock_compatibility.cc +++ b/services/network/initiator_lock_compatibility.cc
@@ -4,8 +4,10 @@ #include "services/network/initiator_lock_compatibility.h" +#include "base/feature_list.h" #include "base/logging.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" +#include "services/network/public/cpp/features.h" #include "services/network/public/cpp/resource_request.h" #include "services/network/public/mojom/network_context.mojom.h" #include "url/gurl.h" @@ -15,20 +17,19 @@ namespace network { InitiatorLockCompatibility VerifyRequestInitiatorLock( - const mojom::URLLoaderFactoryParams& factory_params, - const ResourceRequest& request) { - if (factory_params.process_id == mojom::kBrowserProcessId) - return InitiatorLockCompatibility::kBrowserProcess; - - if (!factory_params.request_initiator_site_lock.has_value()) + const base::Optional<url::Origin>& request_initiator_site_lock, + const base::Optional<url::Origin>& request_initiator) { + if (!request_initiator_site_lock.has_value()) return InitiatorLockCompatibility::kNoLock; - const url::Origin& lock = factory_params.request_initiator_site_lock.value(); + const url::Origin& lock = request_initiator_site_lock.value(); - if (!request.request_initiator.has_value()) { - NOTREACHED(); // Should only happen for the browser process. + if (!request_initiator.has_value()) { + // This should only happen for the browser process (or if NetworkService is + // not enabled). + DCHECK(!base::FeatureList::IsEnabled(network::features::kNetworkService)); return InitiatorLockCompatibility::kNoInitiator; } - const url::Origin& initiator = request.request_initiator.value(); + const url::Origin& initiator = request_initiator.value(); // TODO(lukasza, nasko): Also consider equality of precursor origins (e.g. if // |initiator| is opaque, then it's precursor origin should match the |lock| @@ -57,4 +58,14 @@ return InitiatorLockCompatibility::kIncorrectLock; } +InitiatorLockCompatibility VerifyRequestInitiatorLock( + const mojom::URLLoaderFactoryParams& factory_params, + const ResourceRequest& request) { + if (factory_params.process_id == mojom::kBrowserProcessId) + return InitiatorLockCompatibility::kBrowserProcess; + + return VerifyRequestInitiatorLock(factory_params.request_initiator_site_lock, + request.request_initiator); +} + } // namespace network
diff --git a/services/network/initiator_lock_compatibility.h b/services/network/initiator_lock_compatibility.h index 5e1dba7..6b18910 100644 --- a/services/network/initiator_lock_compatibility.h +++ b/services/network/initiator_lock_compatibility.h
@@ -6,6 +6,8 @@ #define SERVICES_NETWORK_INITIATOR_LOCK_COMPATIBILITY_H_ #include "base/component_export.h" +#include "base/optional.h" +#include "url/origin.h" namespace network { @@ -52,6 +54,10 @@ InitiatorLockCompatibility VerifyRequestInitiatorLock( const mojom::URLLoaderFactoryParams& factory_params, const ResourceRequest& request); +COMPONENT_EXPORT(NETWORK_SERVICE) +InitiatorLockCompatibility VerifyRequestInitiatorLock( + const base::Optional<url::Origin>& request_initiator_site_lock, + const base::Optional<url::Origin>& request_initiator); } // namespace network
diff --git a/services/network/network_service.cc b/services/network/network_service.cc index e4cf802..d22a74c 100644 --- a/services/network/network_service.cc +++ b/services/network/network_service.cc
@@ -22,6 +22,7 @@ #include "mojo/public/cpp/bindings/type_converter.h" #include "net/base/logging_network_change_observer.h" #include "net/base/network_change_notifier.h" +#include "net/base/port_util.h" #include "net/cert/cert_database.h" #include "net/cert/ct_log_response_parser.h" #include "net/cert/signed_tree_head.h" @@ -177,6 +178,13 @@ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + // Set-up the global port overrides. + if (command_line->HasSwitch(switches::kExplicitlyAllowedPorts)) { + std::string allowed_ports = + command_line->GetSwitchValueASCII(switches::kExplicitlyAllowedPorts); + net::SetExplicitlyAllowedPorts(allowed_ports); + } + // Record this once per session, though the switch is appled on a // per-NetworkContext basis. UMA_HISTOGRAM_BOOLEAN(
diff --git a/services/network/public/cpp/network_switches.cc b/services/network/public/cpp/network_switches.cc index 8b2d4ed..60859bc4 100644 --- a/services/network/public/cpp/network_switches.cc +++ b/services/network/public/cpp/network_switches.cc
@@ -49,6 +49,10 @@ // Don't send HTTP-Referer headers. const char kNoReferrers[] = "no-referrers"; +// Allows overriding the list of restricted ports by passing a comma-separated +// list of port numbers. +const char kExplicitlyAllowedPorts[] = "explicitly-allowed-ports"; + } // namespace switches } // namespace network
diff --git a/services/network/public/cpp/network_switches.h b/services/network/public/cpp/network_switches.h index 83e78d0..db64e5a 100644 --- a/services/network/public/cpp/network_switches.h +++ b/services/network/public/cpp/network_switches.h
@@ -20,6 +20,7 @@ COMPONENT_EXPORT(NETWORK_CPP) extern const char kLogNetLog[]; COMPONENT_EXPORT(NETWORK_CPP) extern const char kSSLKeyLogFile[]; COMPONENT_EXPORT(NETWORK_CPP) extern const char kNoReferrers[]; +COMPONENT_EXPORT(NETWORK_CPP) extern const char kExplicitlyAllowedPorts[]; } // namespace switches
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc index a4159d9..3b6253d4 100644 --- a/services/network/url_loader.cc +++ b/services/network/url_loader.cc
@@ -401,11 +401,9 @@ throttling_token_ = network::ScopedThrottlingToken::MaybeCreate( url_request_->net_log().source().id, request.throttling_profile_id); - initiator_lock_compatibility_ = - VerifyRequestInitiatorLock(*factory_params_, request); UMA_HISTOGRAM_ENUMERATION( "NetworkService.URLLoader.RequestInitiatorOriginLockCompatibility", - initiator_lock_compatibility_); + VerifyRequestInitiatorLock(*factory_params_, request)); // TODO(lukasza): Enforce the origin lock. // - https://crbug.com/766694: In the long-term kIncorrectLock should trigger // a renderer kill, but this can't be done until HTML Imports are gone. @@ -799,7 +797,8 @@ corb_analyzer_ = std::make_unique<CrossOriginReadBlocking::ResponseAnalyzer>( - *url_request_, *response_, initiator_lock_compatibility_); + *url_request_, *response_, + factory_params_->request_initiator_site_lock); is_more_corb_sniffing_needed_ = corb_analyzer_->needs_sniffing(); if (corb_analyzer_->ShouldBlock()) { DCHECK(!is_more_corb_sniffing_needed_);
diff --git a/services/network/url_loader.h b/services/network/url_loader.h index 277d8da..5692c241 100644 --- a/services/network/url_loader.h +++ b/services/network/url_loader.h
@@ -247,7 +247,6 @@ // Sniffing state. std::unique_ptr<CrossOriginReadBlocking::ResponseAnalyzer> corb_analyzer_; - InitiatorLockCompatibility initiator_lock_compatibility_; bool is_more_corb_sniffing_needed_ = false; bool is_more_mime_sniffing_needed_ = false;
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 34fb233..11b8dd3 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -144,8 +144,6 @@ #define SK_USE_LEGACY_DISTANCE_FIELDS #endif -#define SK_LEGACY_TESSELLATOR_CPU_COVERAGE - // Skia is enabling this feature soon. Chrome probably does // not want it for M64 #ifndef SK_DISABLE_EXPLICIT_GPU_RESOURCE_ALLOCATION
diff --git a/third_party/blink/perf_tests/resources/runner.js b/third_party/blink/perf_tests/resources/runner.js index a79729a..d1a99ac 100644 --- a/third_party/blink/perf_tests/resources/runner.js +++ b/third_party/blink/perf_tests/resources/runner.js
@@ -136,6 +136,17 @@ finish(); } + PerfTestRunner.formatException = function (text, exception) { + return "Got an exception while " + text + + " with name=" + exception.name + + ", message=" + exception.message + + "\n" + exception.stack; + } + + PerfTestRunner.logException = function (text, exception) { + PerfTestRunner.logFatalError(PerfTestRunner.formatException(text, exception)); + } + PerfTestRunner.forceLayout = function(doc) { doc = doc || document; if (doc.body) @@ -192,7 +203,7 @@ try { runner(); } catch (exception) { - PerfTestRunner.logFatalError("Got an exception while running test.run with name=" + exception.name + ", message=" + exception.message); + PerfTestRunner.logException("running test.run", exception); } return; } @@ -212,7 +223,7 @@ if (currentTest.teardown) currentTest.teardown(); } catch (exception) { - PerfTestRunner.logFatalError("Got an exception while running test.run with name=" + exception.name + ", message=" + exception.message); + PerfTestRunner.logException("running test.run", exception); return; } @@ -221,7 +232,7 @@ try { ignoreWarmUpAndLog(measuredValue); } catch (exception) { - PerfTestRunner.logFatalError("Got an exception while logging the result with name=" + exception.name + ", message=" + exception.message); + PerfTestRunner.logException("logging the result", exception); return; } @@ -260,7 +271,7 @@ if (currentTest.done) currentTest.done(); } catch (exception) { - logInDocument("Got an exception while finalizing the test with name=" + exception.name + ", message=" + exception.message); + logInDocument(PerfTestRunner.formatException("finalizing the test", exception)); } if (window.testRunner) {
diff --git a/third_party/blink/public/platform/web_layer_tree_view.h b/third_party/blink/public/platform/web_layer_tree_view.h index 15dd069a..31758b7 100644 --- a/third_party/blink/public/platform/web_layer_tree_view.h +++ b/third_party/blink/public/platform/web_layer_tree_view.h
@@ -138,9 +138,6 @@ // Flow control and scheduling --------------------------------------- - // Run layout and paint of all pending document changes asynchronously. - virtual void LayoutAndPaintAsync(base::OnceClosure callback) {} - virtual void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) {}
diff --git a/third_party/blink/public/web/web_widget.h b/third_party/blink/public/web/web_widget.h index 981ffea..c5fb93d 100644 --- a/third_party/blink/public/web/web_widget.h +++ b/third_party/blink/public/web/web_widget.h
@@ -139,9 +139,6 @@ // transormations (e.g. pinch-zoom, dev tools emulation, etc.). virtual void PaintContent(cc::PaintCanvas*, const WebRect& view_port) {} - // Run layout and paint of all pending document changes asynchronously. - virtual void LayoutAndPaintAsync(base::OnceClosure callback) {} - // This should only be called when isAcceleratedCompositingActive() is true. virtual void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) {}
diff --git a/third_party/blink/renderer/core/css/resolver/style_resolver.cc b/third_party/blink/renderer/core/css/resolver/style_resolver.cc index b492c41..649913ba 100644 --- a/third_party/blink/renderer/core/css/resolver/style_resolver.cc +++ b/third_party/blink/renderer/core/css/resolver/style_resolver.cc
@@ -1036,10 +1036,8 @@ scoped_refptr<ComputedStyle> StyleResolver::StyleForText(Text* text_node) { DCHECK(text_node); - Node* parent_node = LayoutTreeBuilderTraversal::Parent(*text_node); - if (!parent_node || !parent_node->GetComputedStyle()) - return InitialStyleForElement(GetDocument()); + DCHECK(parent_node); return parent_node->MutableComputedStyle(); }
diff --git a/third_party/blink/renderer/core/editing/selection_controller.cc b/third_party/blink/renderer/core/editing/selection_controller.cc index e4ca6842..a380f8b 100644 --- a/third_party/blink/renderer/core/editing/selection_controller.cc +++ b/third_party/blink/renderer/core/editing/selection_controller.cc
@@ -174,11 +174,11 @@ original_base_in_flat_tree_ = PositionInFlatTreeWithAffinity(); } -static PositionInFlatTree AdjustPositionRespectUserSelectAll( +static PositionInFlatTreeWithAffinity AdjustPositionRespectUserSelectAll( Node* inner_node, const PositionInFlatTree& selection_start, const PositionInFlatTree& selection_end, - const PositionInFlatTree& position) { + const PositionInFlatTreeWithAffinity& position) { const VisibleSelectionInFlatTree& selection_in_user_select_all = CreateVisibleSelection(ExpandSelectionToRespectUserSelectAll( inner_node, @@ -188,9 +188,10 @@ if (!selection_in_user_select_all.IsRange()) return position; if (selection_in_user_select_all.Start().CompareTo(selection_start) < 0) - return selection_in_user_select_all.Start(); + return PositionInFlatTreeWithAffinity(selection_in_user_select_all.Start()); + // TODO(xiaochengh): Do we need to use upstream affinity for end? if (selection_end.CompareTo(selection_in_user_select_all.End()) < 0) - return selection_in_user_select_all.End(); + return PositionInFlatTreeWithAffinity(selection_in_user_select_all.End()); return position; } @@ -211,7 +212,7 @@ } static SelectionInFlatTree ExtendSelectionAsDirectional( - const PositionInFlatTree& position, + const PositionInFlatTreeWithAffinity& position, const SelectionInFlatTree& selection, TextGranularity granularity) { DCHECK(!selection.IsNone()); @@ -219,7 +220,7 @@ const PositionInFlatTree& start = selection.ComputeStartPosition(); const PositionInFlatTree& end = selection.ComputeEndPosition(); const PositionInFlatTree& base = selection.IsBaseFirst() ? start : end; - if (position < base) { + if (position.GetPosition() < base) { // Extend backward yields backward selection // - forward selection: *abc ^def ghi| => |abc def^ ghi // - backward selection: *abc |def ghi^ => |abc def ghi^ @@ -230,9 +231,11 @@ ? ComputeEndRespectingGranularity( new_start, PositionInFlatTreeWithAffinity(start), granularity) : end; - return SelectionInFlatTree::Builder() - .SetBaseAndExtent(new_end, new_start) - .Build(); + SelectionInFlatTree::Builder builder; + builder.SetBaseAndExtent(new_end, new_start); + if (new_start == new_end) + builder.SetAffinity(position.Affinity()); + return builder.Build(); } // Extend forward yields forward selection @@ -244,9 +247,11 @@ : ComputeStartFromEndForExtendForward(end, granularity); const PositionInFlatTree& new_end = ComputeEndRespectingGranularity( new_start, PositionInFlatTreeWithAffinity(position), granularity); - return SelectionInFlatTree::Builder() - .SetBaseAndExtent(new_start, new_end) - .Build(); + SelectionInFlatTree::Builder builder; + builder.SetBaseAndExtent(new_start, new_end); + if (new_start == new_end) + builder.SetAffinity(position.Affinity()); + return builder.Build(); } static SelectionInFlatTree ExtendSelectionAsNonDirectional( @@ -258,6 +263,8 @@ // Shift+Click deselects when selection was created right-to-left const PositionInFlatTree& start = selection.ComputeStartPosition(); const PositionInFlatTree& end = selection.ComputeEndPosition(); + if (start == end && position == start) + return selection; if (position < start) { return SelectionInFlatTree::Builder() .SetBaseAndExtent( @@ -336,10 +343,9 @@ if (extend_selection && !selection.IsNone()) { // Note: "fast/events/shift-click-user-select-none.html" makes // |pos.isNull()| true. - const PositionInFlatTree& adjusted_position = + const PositionInFlatTreeWithAffinity adjusted_position = AdjustPositionRespectUserSelectAll(inner_node, selection.Start(), - selection.End(), - position_to_use.GetPosition()); + selection.End(), position_to_use); const TextGranularity granularity = Selection().Granularity(); if (adjusted_position.IsNull()) { UpdateSelectionForMouseDownDispatchingSelectStart( @@ -352,8 +358,9 @@ frame_->GetEditor().Behavior().ShouldConsiderSelectionAsDirectional() ? ExtendSelectionAsDirectional(adjusted_position, selection.AsSelection(), granularity) - : ExtendSelectionAsNonDirectional( - adjusted_position, selection.AsSelection(), granularity), + : ExtendSelectionAsNonDirectional(adjusted_position.GetPosition(), + selection.AsSelection(), + granularity), SetSelectionOptions::Builder().SetGranularity(granularity).Build()); return false; } @@ -516,10 +523,10 @@ return; } - const PositionInFlatTree& adjusted_position = - AdjustPositionRespectUserSelectAll(target, visible_selection.Start(), - visible_selection.End(), - target_position.DeepEquivalent()); + const PositionInFlatTreeWithAffinity adjusted_position = + AdjustPositionRespectUserSelectAll( + target, visible_selection.Start(), visible_selection.End(), + target_position.ToPositionWithAffinity()); const SelectionInFlatTree& adjusted_selection = should_extend_selection ? ExtendSelectionAsDirectional(adjusted_position,
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc index d8b9b791..8b71a1fc 100644 --- a/third_party/blink/renderer/core/exported/web_page_popup_impl.cc +++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.cc
@@ -575,10 +575,6 @@ return MainFrame().DomWindow(); } -void WebPagePopupImpl::LayoutAndPaintAsync(base::OnceClosure callback) { - layer_tree_view_->LayoutAndPaintAsync(std::move(callback)); -} - void WebPagePopupImpl::CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) { DCHECK(IsAcceleratedCompositingActive());
diff --git a/third_party/blink/renderer/core/exported/web_page_popup_impl.h b/third_party/blink/renderer/core/exported/web_page_popup_impl.h index efdb66a..f8b1ec81 100644 --- a/third_party/blink/renderer/core/exported/web_page_popup_impl.h +++ b/third_party/blink/renderer/core/exported/web_page_popup_impl.h
@@ -68,7 +68,6 @@ return other && popup_client_ == other->popup_client_; } LocalDOMWindow* Window(); - void LayoutAndPaintAsync(base::OnceClosure callback) override; void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) override; WebPoint PositionRelativeToOwner() override;
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc index 6a695832..9f45d48 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.cc +++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -1610,11 +1610,6 @@ *page_->DeprecatedLocalMainFrame()); } -void WebViewImpl::LayoutAndPaintAsync(base::OnceClosure callback) { - if (layer_tree_view_) - layer_tree_view_->LayoutAndPaintAsync(std::move(callback)); -} - void WebViewImpl::CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) { if (layer_tree_view_)
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.h b/third_party/blink/renderer/core/exported/web_view_impl.h index a2b2c17..b6ba2a2 100644 --- a/third_party/blink/renderer/core/exported/web_view_impl.h +++ b/third_party/blink/renderer/core/exported/web_view_impl.h
@@ -439,7 +439,6 @@ void RequestPresentationCallbackForTesting( base::OnceClosure callback) override; void PaintContent(cc::PaintCanvas*, const WebRect&) override; - void LayoutAndPaintAsync(base::OnceClosure callback) override; void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) override; void ThemeChanged() override;
diff --git a/third_party/blink/renderer/core/frame/link_highlights.h b/third_party/blink/renderer/core/frame/link_highlights.h index 075bd99f..fc58e13e 100644 --- a/third_party/blink/renderer/core/frame/link_highlights.h +++ b/third_party/blink/renderer/core/frame/link_highlights.h
@@ -69,6 +69,7 @@ FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, verifyWebViewImplIntegration); FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, resetDuringNodeRemoval); FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, resetLayerTreeView); + FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, HighlightInvalidation); FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, multipleHighlights); FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, HighlightLayerEffectNode); FRIEND_TEST_ALL_PREFIXES(LinkHighlightImplTest, MultiColumn);
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc index 53fd46d..f927f69 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.cc
@@ -337,10 +337,6 @@ 1, View()->MinimumPageScaleFactor(), View()->MaximumPageScaleFactor()); } -void WebFrameWidgetImpl::LayoutAndPaintAsync(base::OnceClosure callback) { - layer_tree_view_->LayoutAndPaintAsync(std::move(callback)); -} - void WebFrameWidgetImpl::CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) { layer_tree_view_->CompositeAndReadbackAsync(std::move(callback));
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h index c30359f0..622592b 100644 --- a/third_party/blink/renderer/core/frame/web_frame_widget_impl.h +++ b/third_party/blink/renderer/core/frame/web_frame_widget_impl.h
@@ -89,7 +89,6 @@ void UpdateLifecycle(LifecycleUpdate requested_update, LifecycleUpdateReason reason) override; void PaintContent(cc::PaintCanvas*, const WebRect&) override; - void LayoutAndPaintAsync(base::OnceClosure callback) override; void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) override; void ThemeChanged() override;
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc index 6f2aa599..a762ca2c 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.cc +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.cc
@@ -70,10 +70,6 @@ web_view_->PaintContent(canvas, view_port); } -void WebViewFrameWidget::LayoutAndPaintAsync(base::OnceClosure callback) { - web_view_->LayoutAndPaintAsync(std::move(callback)); -} - void WebViewFrameWidget::CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)> callback) { web_view_->CompositeAndReadbackAsync(std::move(callback));
diff --git a/third_party/blink/renderer/core/frame/web_view_frame_widget.h b/third_party/blink/renderer/core/frame/web_view_frame_widget.h index 2d41ec8..2ec4c80 100644 --- a/third_party/blink/renderer/core/frame/web_view_frame_widget.h +++ b/third_party/blink/renderer/core/frame/web_view_frame_widget.h
@@ -53,7 +53,6 @@ void UpdateLifecycle(LifecycleUpdate requested_update, LifecycleUpdateReason reason) override; void PaintContent(cc::PaintCanvas*, const WebRect& view_port) override; - void LayoutAndPaintAsync(base::OnceClosure callback) override; void CompositeAndReadbackAsync( base::OnceCallback<void(const SkBitmap&)>) override; void ThemeChanged() override;
diff --git a/third_party/blink/renderer/core/layout/layout_block.cc b/third_party/blink/renderer/core/layout/layout_block.cc index 3b67df83..f9ecbe3a4 100644 --- a/third_party/blink/renderer/core/layout/layout_block.cc +++ b/third_party/blink/renderer/core/layout/layout_block.cc
@@ -1051,6 +1051,24 @@ BlockPaintInvalidator(*this).ClearPreviousVisualRects(); } +void LayoutBlock::ImageChanged(WrappedImagePtr image, + CanDeferInvalidation defer) { + LayoutBox::ImageChanged(image, defer); + + if (!StyleRef().HasPseudoStyle(kPseudoIdFirstLine)) + return; + + if (auto* first_line_container = NearestInnerBlockWithFirstLine()) { + for (const auto* layer = &FirstLineStyleRef().BackgroundLayers(); layer; + layer = layer->Next()) { + if (layer->GetImage() && image == layer->GetImage()->Data()) { + first_line_container->SetShouldDoFullPaintInvalidationForFirstLine(); + break; + } + } + } +} + void LayoutBlock::RemovePositionedObjects( LayoutObject* o, ContainingBlockState containing_block_state) {
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h index d5fe0eed..5422b712 100644 --- a/third_party/blink/renderer/core/layout/layout_block.h +++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -518,9 +518,10 @@ protected: void InvalidatePaint(const PaintInvalidatorContext&) const override; - void ClearPreviousVisualRects() override; + void ImageChanged(WrappedImagePtr, CanDeferInvalidation) override; + private: LayoutRect LocalCaretRect( const InlineBox*,
diff --git a/third_party/blink/renderer/core/layout/layout_object.cc b/third_party/blink/renderer/core/layout/layout_object.cc index 82962bd..9bf6348d 100644 --- a/third_party/blink/renderer/core/layout/layout_object.cc +++ b/third_party/blink/renderer/core/layout/layout_object.cc
@@ -1965,39 +1965,6 @@ SetStyle(std::move(pseudo_style)); } -void LayoutObject::FirstLineStyleDidChange(const ComputedStyle& old_style, - const ComputedStyle& new_style) { - StyleDifference diff = - old_style.VisualInvalidationDiff(GetDocument(), new_style); - - if (diff.NeedsFullPaintInvalidation() || - diff.TextDecorationOrColorChanged()) { - // We need to invalidate all inline boxes in the first line, because they - // need to be repainted with the new style, e.g. background, font style, - // etc. - LayoutBlockFlow* first_line_container = nullptr; - if (BehavesLikeBlockContainer()) { - // This object is a LayoutBlock having PseudoIdFirstLine pseudo style - // changed. - first_line_container = - ToLayoutBlock(this)->NearestInnerBlockWithFirstLine(); - } else if (IsLayoutInline()) { - // This object is a LayoutInline having FIRST_LINE_INHERITED pesudo style - // changed. This method can be called even if the LayoutInline doesn't - // intersect the first line, but we only need to invalidate if it does. - if (InlineBox* first_line_box = - ToLayoutInline(this)->FirstLineBoxIncludingCulling()) { - if (first_line_box->IsFirstLineStyle()) - first_line_container = ToLayoutBlockFlow(ContainingBlock()); - } - } - if (first_line_container) - first_line_container->SetShouldDoFullPaintInvalidationForFirstLine(); - } - if (diff.NeedsLayout()) - SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange); -} - void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded() { LayoutObject* object = this; do { @@ -2047,9 +2014,9 @@ SetStyleInternal(std::move(style)); UpdateFillImages(old_style ? &old_style->BackgroundLayers() : nullptr, - style_->BackgroundLayers()); + &style_->BackgroundLayers()); UpdateFillImages(old_style ? &old_style->MaskLayers() : nullptr, - style_->MaskLayers()); + &style_->MaskLayers()); UpdateImage(old_style ? old_style->BorderImage().GetImage() : nullptr, style_->BorderImage().GetImage()); @@ -2352,8 +2319,7 @@ SetBackgroundNeedsFullPaintInvalidation(); } - if (old_style && old_style->StyleType() == kPseudoIdNone) - ApplyPseudoStyleChanges(*old_style); + ApplyPseudoStyleChanges(old_style); if (old_style && old_style->UsedTransformStyle3D() != StyleRef().UsedTransformStyle3D()) { @@ -2363,30 +2329,57 @@ } } -void LayoutObject::ApplyPseudoStyleChanges(const ComputedStyle& old_style) { - if (old_style.HasPseudoStyle(kPseudoIdFirstLine) || +void LayoutObject::ApplyPseudoStyleChanges(const ComputedStyle* old_style) { + if ((old_style && old_style->HasPseudoStyle(kPseudoIdFirstLine)) || StyleRef().HasPseudoStyle(kPseudoIdFirstLine)) ApplyFirstLineChanges(old_style); - if (old_style.HasPseudoStyle(kPseudoIdSelection) || + if ((old_style && old_style->HasPseudoStyle(kPseudoIdSelection)) || StyleRef().HasPseudoStyle(kPseudoIdSelection)) InvalidateSelectedChildrenOnStyleChange(); } -void LayoutObject::ApplyFirstLineChanges(const ComputedStyle& old_style) { - if (old_style.HasPseudoStyle(kPseudoIdFirstLine)) { - scoped_refptr<const ComputedStyle> old_pseudo_style = - old_style.GetCachedPseudoStyle(kPseudoIdFirstLine); - if (StyleRef().HasPseudoStyle(kPseudoIdFirstLine) && old_pseudo_style) { - scoped_refptr<const ComputedStyle> new_pseudo_style = - UncachedFirstLineStyle(); - if (new_pseudo_style) { - FirstLineStyleDidChange(*old_pseudo_style, *new_pseudo_style); - return; - } - } +void LayoutObject::ApplyFirstLineChanges(const ComputedStyle* old_style) { + DCHECK((old_style && old_style->HasPseudoStyle(kPseudoIdFirstLine)) || + StyleRef().HasPseudoStyle(kPseudoIdFirstLine)); + + const ComputedStyle* old_first_line_style = nullptr; + if (old_style && old_style->HasPseudoStyle(kPseudoIdFirstLine)) + old_first_line_style = old_style->GetCachedPseudoStyle(kPseudoIdFirstLine); + else + old_first_line_style = old_style; + + auto new_first_line_style = UncachedFirstLineStyle(); + if (!old_first_line_style && !new_first_line_style) + return; + + UpdateFillImages( + old_first_line_style ? &old_first_line_style->BackgroundLayers() + : nullptr, + new_first_line_style ? &new_first_line_style->BackgroundLayers() + : nullptr); + + StyleDifference diff; + bool has_diff = false; + if (old_first_line_style && new_first_line_style) { + diff = old_first_line_style->VisualInvalidationDiff(GetDocument(), + *new_first_line_style); + has_diff = true; } - SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange); + if (!has_diff) { + diff.SetNeedsPaintInvalidationObject(); + diff.SetNeedsFullLayout(); + } + + if (BehavesLikeBlockContainer() && (diff.NeedsFullPaintInvalidation() || + diff.TextDecorationOrColorChanged())) { + if (auto* first_line_container = + ToLayoutBlock(this)->NearestInnerBlockWithFirstLine()) + first_line_container->SetShouldDoFullPaintInvalidationForFirstLine(); + } + + if (diff.NeedsLayout()) + SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange); } void LayoutObject::PropagateStyleToAnonymousChildren() { @@ -2460,14 +2453,14 @@ } void LayoutObject::UpdateFillImages(const FillLayer* old_layers, - const FillLayer& new_layers) { + const FillLayer* new_layers) { // Optimize the common case - if (FillLayer::ImagesIdentical(old_layers, &new_layers)) + if (FillLayer::ImagesIdentical(old_layers, new_layers)) return; // Go through the new layers and addClients first, to avoid removing all // clients of an image. - for (const FillLayer* curr_new = &new_layers; curr_new; + for (const FillLayer* curr_new = new_layers; curr_new; curr_new = curr_new->Next()) { if (curr_new->GetImage()) curr_new->GetImage()->AddClient(this); @@ -3550,6 +3543,12 @@ PseudoStyleRequest(kPseudoIdFirstLine), style); } } else if (layout_object_for_first_line_style->IsLayoutInline()) { + if (!layout_object_for_first_line_style->Parent()) { + // The logic below applies only when this object has parent, while this + // function can be called from ApplyFirstLineChanges() when the object + // has not been set a parent yet. + return nullptr; + } if (layout_object_for_first_line_style->IsAnonymous()) { // Anonymous inline box for ::first-line should inherit background. if (ToLayoutInline(layout_object_for_first_line_style) @@ -3586,11 +3585,9 @@ scoped_refptr<const ComputedStyle> LayoutObject::UncachedFirstLineStyle() const { - if (!GetDocument().GetStyleEngine().UsesFirstLineRules()) - return nullptr; - + // Don't check GetDocument().GetStyleEngine().UsesFirstLineRules() because + // this object may not have access to GetDocument() yet during initialization. DCHECK(!IsText()); - return FirstLineStyleForCachedUncachedType(kUncached, this, style_.get()); }
diff --git a/third_party/blink/renderer/core/layout/layout_object.h b/third_party/blink/renderer/core/layout/layout_object.h index 1467118..f47806a 100644 --- a/third_party/blink/renderer/core/layout/layout_object.h +++ b/third_party/blink/renderer/core/layout/layout_object.h
@@ -1327,9 +1327,6 @@ LayoutObject* parent); void SetStyleWithWritingModeOfParent(scoped_refptr<ComputedStyle>); - void FirstLineStyleDidChange(const ComputedStyle& old_style, - const ComputedStyle& new_style); - void ClearBaseComputedStyle(); // This function returns an enclosing non-anonymous LayoutBlock for this @@ -2388,7 +2385,7 @@ void UpdateShapeImage(const ShapeValue*, const ShapeValue*); void UpdateFillImages(const FillLayer* old_layers, - const FillLayer& new_layers); + const FillLayer* new_layers); void UpdateCursorImages(const CursorList* old_cursors, const CursorList* new_cursors); void CheckCounterChanges(const ComputedStyle* old_style, @@ -2434,8 +2431,8 @@ // LayoutView to return the owning LayoutObject in the containing frame. inline LayoutObject* ParentCrossingFrames() const; - void ApplyPseudoStyleChanges(const ComputedStyle& old_style); - void ApplyFirstLineChanges(const ComputedStyle& old_style); + void ApplyPseudoStyleChanges(const ComputedStyle* old_style); + void ApplyFirstLineChanges(const ComputedStyle* old_style); LayoutRect VisualRectForInlineBox() const { return AdjustVisualRectForInlineBox(VisualRect());
diff --git a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h index 4a128618..94d59f3b 100644 --- a/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h +++ b/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -57,7 +57,7 @@ return *this; } - NGBoxStrut operator+(const NGBoxStrut& other) { + NGBoxStrut operator+(const NGBoxStrut& other) const { NGBoxStrut result(*this); result += other; return result; @@ -71,7 +71,7 @@ return *this; } - NGBoxStrut operator-(const NGBoxStrut& other) { + NGBoxStrut operator-(const NGBoxStrut& other) const { NGBoxStrut result(*this); result -= other; return result;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc index 79aa5c4..67245b0 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -45,6 +45,13 @@ return !item_results.IsEmpty() && item_results.back().has_unpositioned_floats; } +bool IsImage(const NGInlineItem& item) { + if (!item.GetLayoutObject() || !item.GetLayoutObject()->IsLayoutImage()) + return false; + DCHECK(item.Type() == NGInlineItem::kAtomicInline); + return true; +} + } // namespace NGLineBreaker::NGLineBreaker(NGInlineNode node, @@ -86,6 +93,19 @@ items_data_.AssertOffset(item_index_, offset_); ignore_floats_ = break_token->IgnoreFloats(); } + + // There's a special intrinsic size measure quirk for images that are direct + // children of table cells that have auto inline-size: When measuring + // intrinsic min/max inline sizes, we pretend that it's not possible to break + // between images, or between text and images. Note that this only applies + // when measuring. During actual layout, on the other hand, standard breaking + // rules are to be followed. + // See https://quirks.spec.whatwg.org/#the-table-cell-width-calculation-quirk + if (node.GetDocument().InQuirksMode() && + node.Style().Display() == EDisplay::kTableCell && + node.Style().LogicalWidth().IsIntrinsicOrAuto() && + mode != NGLineBreakerMode::kContent) + sticky_images_quirk_ = true; } // Define the destructor here, so that we can forward-declare more in the @@ -277,6 +297,15 @@ // opportunity if we're trailing. if (state_ == LineBreakState::kTrailing && CanBreakAfterLast(*item_results_)) { + if (sticky_images_quirk_ && IsImage(item) && + (trailing_whitespace_ == WhitespaceState::kNone || + trailing_whitespace_ == WhitespaceState::kUnknown)) { + // If this is an image that follows text that doesn't end with something + // breakable, we cannot break between the two items. + HandleAtomicInline(item); + continue; + } + line_info_->SetIsLastLine(false); return; } @@ -878,6 +907,19 @@ trailing_whitespace_ = WhitespaceState::kNone; position_ += item_result->inline_size; ComputeCanBreakAfter(item_result); + + if (sticky_images_quirk_ && IsImage(item)) { + const auto& items = Items(); + if (item_index_ + 1 < items.size()) { + DCHECK_EQ(&item, &items[item_index_]); + const auto& next_item = items[item_index_ + 1]; + // This is an image, and we don't want to break after it, unless what + // comes after provides a break opportunity. Look ahead. We only want to + // break if the next item is an atomic inline that's not an image. + if (next_item.Type() != NGInlineItem::kAtomicInline || IsImage(next_item)) + item_result->can_break_after = false; + } + } MoveToNextOf(item); }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h index 04ed7efb..b483011 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -202,6 +202,10 @@ bool ignore_floats_ = false; + // Set in quirks mode when we're not supposed to break inside table cells + // between images, and between text and images. + bool sticky_images_quirk_ = false; + const NGInlineItemsData& items_data_; NGLineBreakerMode mode_;
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc index a944c30..a60e9b1b 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -30,24 +30,6 @@ LayoutNGMixin<LayoutBlockFlow>::IsOfType(type); } -void LayoutNGBlockFlow::ComputeIntrinsicLogicalWidths( - LayoutUnit& min_logical_width, - LayoutUnit& max_logical_width) const { - NGBlockNode node(const_cast<LayoutNGBlockFlow*>(this)); - if (!node.CanUseNewLayout()) { - LayoutBlockFlow::ComputeIntrinsicLogicalWidths(min_logical_width, - max_logical_width); - return; - } - MinMaxSizeInput input; - // This function returns content-box plus scrollbar. - input.size_type = NGMinMaxSizeType::kContentBoxSize; - MinMaxSize sizes = node.ComputeMinMaxSize(StyleRef().GetWritingMode(), input); - sizes += LayoutUnit(ScrollbarLogicalWidth()); - min_logical_width = sizes.min_size; - max_logical_width = sizes.max_size; -} - void LayoutNGBlockFlow::UpdateBlockLayout(bool relayout_children) { LayoutAnalyzer::BlockScope analyzer(*this);
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h index 4f552c1..f36533ea2 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h
@@ -24,11 +24,6 @@ protected: bool IsOfType(LayoutObjectType) const override; - protected: - void ComputeIntrinsicLogicalWidths( - LayoutUnit& min_logical_width, - LayoutUnit& max_logical_width) const override; - private: void UpdateOutOfFlowBlockLayout(); };
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc index 7759f35..5935a2a 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -72,8 +72,40 @@ } template <typename Base> -void LayoutNGMixin<Base>::ComputeVisualOverflow( - bool recompute_floats) { +void LayoutNGMixin<Base>::ComputeIntrinsicLogicalWidths( + LayoutUnit& min_logical_width, + LayoutUnit& max_logical_width) const { + NGBlockNode node(const_cast<LayoutNGMixin<Base>*>(this)); + if (!node.CanUseNewLayout()) { + Base::ComputeIntrinsicLogicalWidths(min_logical_width, max_logical_width); + return; + } + MinMaxSizeInput input; + // This function returns content-box plus scrollbar. + input.size_type = NGMinMaxSizeType::kContentBoxSize; + MinMaxSize sizes = + node.ComputeMinMaxSize(node.Style().GetWritingMode(), input); + + if (Base::IsTableCell()) { + // If a table cell, or the column that it belongs to, has a specified fixed + // positive inline-size, and the measured intrinsic max size is less than + // that, use specified size as max size. + LayoutTableCell* cell = ToLayoutTableCell(node.GetLayoutBox()); + Length table_cell_width = cell->StyleOrColLogicalWidth(); + if (table_cell_width.IsFixed() && table_cell_width.Value() > 0) { + sizes.max_size = std::max(sizes.min_size, + Base::AdjustContentBoxLogicalWidthForBoxSizing( + LayoutUnit(table_cell_width.Value()))); + } + } + + sizes += LayoutUnit(Base::ScrollbarLogicalWidth()); + min_logical_width = sizes.min_size; + max_logical_width = sizes.max_size; +} + +template <typename Base> +void LayoutNGMixin<Base>::ComputeVisualOverflow(bool recompute_floats) { LayoutRect previous_visual_overflow_rect = Base::VisualOverflowRect(); Base::ClearVisualOverflow(); Base::ComputeVisualOverflow(recompute_floats);
diff --git a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h index 502ac6d3..ace5295 100644 --- a/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h +++ b/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -83,6 +83,10 @@ protected: bool IsOfType(LayoutObject::LayoutObjectType) const override; + void ComputeIntrinsicLogicalWidths( + LayoutUnit& min_logical_width, + LayoutUnit& max_logical_width) const override; + void ComputeVisualOverflow(bool recompute_floats) final; void AddVisualOverflowFromChildren();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc index 7afc944..743d54b 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -22,7 +22,12 @@ NGFlexLayoutAlgorithm::NGFlexLayoutAlgorithm(NGBlockNode node, const NGConstraintSpace& space, const NGBreakToken* break_token) - : NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) { + : NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)), + border_scrollbar_padding_( + CalculateBorderScrollbarPadding(ConstraintSpace(), Node())), + borders_(ComputeBorders(ConstraintSpace(), Style())), + padding_(ComputePadding(ConstraintSpace(), Style())), + is_column_(Style().IsColumnFlexDirection()) { container_builder_.SetIsNewFormattingContext(space.IsNewFormattingContext()); } @@ -55,22 +60,14 @@ } scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() { - DCHECK(!NeedMinMaxSize(ConstraintSpace(), Style())) - << "Don't support that yet"; - - borders_ = ComputeBorders(ConstraintSpace(), Style()); - padding_ = ComputePadding(ConstraintSpace(), Style()); // TODO(dgrogan): Pass padding+borders as optimization. border_box_size_ = CalculateBorderBoxSize(ConstraintSpace(), Node()); - border_scrollbar_padding_ = - CalculateBorderScrollbarPadding(ConstraintSpace(), Node()); content_box_size_ = ShrinkAvailableSize(border_box_size_, border_scrollbar_padding_); const LayoutUnit line_break_length = MainAxisContentExtent(LayoutUnit::Max()); FlexLayoutAlgorithm algorithm(&Style(), line_break_length); - bool is_column = Style().IsColumnFlexDirection(); - bool is_horizontal_flow = algorithm.IsHorizontalFlow(); + const bool is_horizontal_flow = algorithm.IsHorizontalFlow(); for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child; generic_child = generic_child.NextSibling()) { @@ -200,7 +197,7 @@ LayoutUnit main_axis_offset = border_scrollbar_padding_.inline_start; LayoutUnit cross_axis_offset = border_scrollbar_padding_.block_start; - if (is_column) { + if (is_column_) { main_axis_offset = border_scrollbar_padding_.block_start; cross_axis_offset = border_scrollbar_padding_.inline_start; } @@ -225,7 +222,7 @@ &space_builder); NGLogicalSize available_size; - if (is_column) { + if (is_column_) { available_size.inline_size = content_box_size_.inline_size; available_size.block_size = flex_item.flexed_content_size + flex_item.main_axis_border_and_padding; @@ -256,8 +253,8 @@ std::max(max_main_axis_extent, line->main_axis_extent); } LayoutUnit intrinsic_block_content_size = - is_column ? max_main_axis_extent - : cross_axis_offset - border_scrollbar_padding_.block_start; + is_column_ ? max_main_axis_extent + : cross_axis_offset - border_scrollbar_padding_.block_start; LayoutUnit intrinsic_block_size = intrinsic_block_content_size + border_scrollbar_padding_.BlockSum(); LayoutUnit block_size = ComputeBlockSizeForFragment( @@ -268,7 +265,7 @@ // container-specific local variables into data members. LayoutUnit final_content_cross_size = block_size - border_scrollbar_padding_.BlockSum(); - if (is_column) { + if (is_column_) { final_content_cross_size = border_box_size_.inline_size - border_scrollbar_padding_.InlineSum(); } @@ -293,7 +290,7 @@ NGLogicalSize available_size(flex_item.flexed_content_size + flex_item.main_axis_border_and_padding, flex_item.cross_axis_size); - if (is_column) + if (is_column_) available_size.Flip(); space_builder.SetAvailableSize(available_size); space_builder.SetPercentageResolutionSize(content_box_size_); @@ -325,8 +322,55 @@ base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize( const MinMaxSizeInput& input) const { - // TODO(dgrogan): Implement this. - return base::nullopt; + MinMaxSize sizes; + if (Node().ShouldApplySizeContainment()) { + // TODO(dgrogan): When this code was written it didn't make any more tests + // pass, so it may be wrong or untested. + if (input.size_type == NGMinMaxSizeType::kBorderBoxSize) + sizes = border_scrollbar_padding_.InlineSum(); + return sizes; + } + + for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child; + generic_child = generic_child.NextSibling()) { + NGBlockNode child = ToNGBlockNode(generic_child); + if (child.IsOutOfFlowPositioned()) + continue; + // Use default MinMaxSizeInput: + // - Children of flexbox ignore any specified float properties, so + // children never have to take floated siblings into account, and + // external floats don't make it through the new formatting context that + // flexbox establishes. + // - We want the child's border box MinMaxSize, which is the default. + MinMaxSize child_min_max_sizes = + ComputeMinAndMaxContentContribution(Style(), child, MinMaxSizeInput()); + NGBoxStrut child_margins = ComputeMinMaxMargins(Style(), child); + child_min_max_sizes += child_margins.InlineSum(); + if (is_column_) { + sizes.min_size = std::max(sizes.min_size, child_min_max_sizes.min_size); + sizes.max_size = std::max(sizes.max_size, child_min_max_sizes.max_size); + } else { + sizes.max_size += child_min_max_sizes.max_size; + if (IsMultiline()) + sizes.min_size = std::max(sizes.min_size, child_min_max_sizes.min_size); + else + sizes.min_size += child_min_max_sizes.min_size; + } + } + sizes.max_size = std::max(sizes.max_size, sizes.min_size); + + // Due to negative margins, it is possible that we calculated a negative + // intrinsic width. Make sure that we never return a negative width. + sizes.Encompass(LayoutUnit()); + + if (input.size_type == NGMinMaxSizeType::kBorderBoxSize) + sizes += border_scrollbar_padding_.InlineSum(); + + return sizes; +} + +bool NGFlexLayoutAlgorithm::IsMultiline() const { + return Style().FlexWrap() != EFlexWrap::kNowrap; } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h index 04652cd..e10d18f 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
@@ -37,12 +37,17 @@ LayoutUnit MainAxisContentExtent(LayoutUnit sum_hypothetical_main_size); void HandleOutOfFlowPositioned(NGBlockNode child); + // TODO(dgrogan): This is redundant with FlexLayoutAlgorithm.IsMultiline() but + // it's needed before the algorithm is instantiated. Figure out how to + // not reimplement. + bool IsMultiline() const; + const NGBoxStrut border_scrollbar_padding_; + const NGBoxStrut borders_; + const NGBoxStrut padding_; + const bool is_column_; NGLogicalSize border_box_size_; - NGBoxStrut border_scrollbar_padding_; NGLogicalSize content_box_size_; - NGBoxStrut borders_; - NGBoxStrut padding_; }; } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context.h b/third_party/blink/renderer/core/loader/frame_fetch_context.h index ed19927..05dcdde 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context.h +++ b/third_party/blink/renderer/core/loader/frame_fetch_context.h
@@ -180,6 +180,14 @@ struct FrozenState; + // TODO(altimin): This is used when creating a URLLoader, and + // FetchContext::GetLoadingTaskRunner is used whenever asynchronous tasks + // around resource loading are posted. Modify the code so that all + // the tasks related to loading a resource use the resource loader handle's + // task runner. + std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle> + CreateResourceLoadingTaskRunnerHandle(); + // Convenient accessors below can be used to transparently access the // relevant document loader or frame in either cases without null-checks. // @@ -191,8 +199,6 @@ // FetchContext overrides: FrameScheduler* GetFrameScheduler() const override; - std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle> - CreateResourceLoadingTaskRunnerHandle() override; // BaseFetchContext overrides: KURL GetSiteForCookies() const override;
diff --git a/third_party/blink/renderer/core/loader/worker_fetch_context.h b/third_party/blink/renderer/core/loader/worker_fetch_context.h index 7ba2a2f..4357aeb 100644 --- a/third_party/blink/renderer/core/loader/worker_fetch_context.h +++ b/third_party/blink/renderer/core/loader/worker_fetch_context.h
@@ -110,8 +110,13 @@ ResourceRequest&) override; bool DefersLoading() const override; - std::unique_ptr<scheduler::WebResourceLoadingTaskRunnerHandle> - CreateResourceLoadingTaskRunnerHandle() override; + // TODO(altimin): This is used when creating a URLLoader, and + // FetchContext::GetLoadingTaskRunner is used whenever asynchronous tasks + // around resource loading are posted. Modify the code so that all + // the tasks related to loading a resource use the resource loader handle's + // task runner. + std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle> + CreateResourceLoadingTaskRunnerHandle(); SecurityContext& GetSecurityContext() const; WorkerSettings* GetWorkerSettings() const;
diff --git a/third_party/blink/renderer/core/paint/README.md b/third_party/blink/renderer/core/paint/README.md index ce3acf4d..dbf3dc08 100644 --- a/third_party/blink/renderer/core/paint/README.md +++ b/third_party/blink/renderer/core/paint/README.md
@@ -574,7 +574,7 @@ `::first-line` style and the style of the `LayoutInline` and apply the computed style to the first line part of the `LayoutInline`. In Blink's style implementation, the combined first line style of `LayoutInline` is identified -with `FIRST_LINE_INHERITED` pseudo ID. +with `kPseudoIdFirstLineInherited`. The normal paint invalidation of texts doesn't work for first line because * `ComputedStyle::VisualInvalidationDiff()` can't detect first line style
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl.cc b/third_party/blink/renderer/core/paint/link_highlight_impl.cc index a4ee479..93b5985 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl.cc +++ b/third_party/blink/renderer/core/paint/link_highlight_impl.cc
@@ -386,10 +386,9 @@ Layer()->SetNeedsDisplay(); if (current_graphics_layer_) { - gfx::Rect rect = gfx::ToEnclosingRect( - gfx::RectF(Layer()->position(), gfx::SizeF(Layer()->bounds()))); + IntRect rect = IntRect(IntPoint(), IntSize(Layer()->bounds())); current_graphics_layer_->TrackRasterInvalidation( - *this, IntRect(rect), PaintInvalidationReason::kFullLayer); + *this, rect, PaintInvalidationReason::kFullLayer); } } }
diff --git a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc index 414f1c7..d3da4806 100644 --- a/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc +++ b/third_party/blink/renderer/core/paint/link_highlight_impl_test.cc
@@ -248,6 +248,44 @@ } } +TEST_P(LinkHighlightImplTest, HighlightInvalidation) { + // This test requires GraphicsLayers which are not used in + // CompositeAfterPaint. + if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) + return; + + WebViewImpl* web_view_impl = web_view_helper_.GetWebView(); + web_view_impl->MainFrameWidget()->Resize(WebSize(640, 480)); + UpdateAllLifecyclePhases(); + + WebGestureEvent touch_event(WebInputEvent::kGestureShowPress, + WebInputEvent::kNoModifiers, + WebInputEvent::GetStaticTimeStampForTests(), + kWebGestureDeviceTouchscreen); + touch_event.SetPositionInWidget(WebFloatPoint(20, 20)); + GestureEventWithHitTestResults targeted_event = GetTargetedEvent(touch_event); + auto* touch_element = ToElement(web_view_impl->BestTapNode(targeted_event)); + web_view_impl->EnableTapHighlightAtPoint(targeted_event); + + web_view_helper_.LocalMainFrame() + ->GetFrameView() + ->SetTracksPaintInvalidations(true); + + // Change the touched element's height to 12px. + auto& style = touch_element->getAttribute(html_names::kStyleAttr); + String new_style = style.GetString(); + new_style.append("height: 12px;"); + touch_element->setAttribute(html_names::kStyleAttr, AtomicString(new_style)); + UpdateAllLifecyclePhases(); + + const auto& highlights = + web_view_impl->GetPage()->GetLinkHighlights().link_highlights_; + auto* highlight_layer = highlights.at(0)->CurrentGraphicsLayerForTesting(); + const auto* tracking = highlight_layer->GetRasterInvalidationTracking(); + // The invalidation rect should fully cover the layer. + EXPECT_EQ(tracking->Invalidations().back().rect, IntRect(0, 0, 200, 12)); +} + TEST_P(LinkHighlightImplTest, HighlightLayerEffectNode) { // This is testing the blink->cc layer integration. if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index 95f3227..bafc1fb51 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -553,8 +553,11 @@ bool needs_end_layer = false; if (!painting_overflow_contents) { + bool skip_background = layout_box.BackgroundTransfersToView() || + (paint_info.SkipRootBackground() && + paint_info.PaintContainer() == layout_box); PaintNormalBoxShadow(paint_info, paint_rect, style, border_edges_.line_left, - border_edges_.line_right); + border_edges_.line_right, skip_background); if (box_fragment_.HasSelfPaintingLayer() && layout_box.IsTableCell() && ToLayoutTableCell(layout_box).Table()->ShouldCollapseBorders()) {
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js b/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js index e60c72bf..09f2ed55 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js +++ b/third_party/blink/renderer/devtools/front_end/profiler/HeapTimelineOverview.js
@@ -231,9 +231,9 @@ const minIndex = timestamps.lowerBound(timeLeft); const maxIndex = timestamps.upperBound(timeRight); let size = 0; - for (let i = minIndex; i < maxIndex; ++i) + for (let i = minIndex; i <= maxIndex; ++i) size += sizes[i]; - const minId = minIndex < ids.length ? ids[minIndex] : Infinity; + const minId = minIndex > 0 ? ids[minIndex - 1] : 0; const maxId = maxIndex < ids.length ? ids[maxIndex] : Infinity; this.dispatchEventToListeners(Profiler.HeapTimelineOverview.IdsRangeChanged, {minId, maxId, size});
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc b/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc index 9757b584..0d48626 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc +++ b/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.cc
@@ -53,6 +53,12 @@ void DtlsTransportProxy::OnStateChange(webrtc::DtlsTransportInformation info) { DCHECK(host_thread_->BelongsToCurrentThread()); + // Closed is the last state that can happen, so unregister when we see this. + // Unregistering allows us to safely delete the proxy independent of the + // state of the webrtc::DtlsTransport. + if (info.state() == webrtc::DtlsTransportState::kClosed) { + dtls_transport_->UnregisterObserver(); + } PostCrossThreadTask(*proxy_thread_, FROM_HERE, CrossThreadBind(&Delegate::OnStateChange, CrossThreadUnretained(delegate_), info));
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h b/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h index c38cd2a9..0d837e8 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h +++ b/third_party/blink/renderer/modules/peerconnection/adapters/dtls_transport_proxy.h
@@ -38,6 +38,9 @@ // Constructs a DtlsTransportProxy. // The caller is responsible for keeping |dtls_transport| and |delegate| // alive until after the DtlsTransportProxy is deleted. + // The DtlsTransportProxy can be safely deleted after seeing the + // state |kClosed|, since this is the last event that can happen + // on the transport. static std::unique_ptr<DtlsTransportProxy> Create( LocalFrame& frame, scoped_refptr<base::SingleThreadTaskRunner> proxy_thread,
diff --git a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc index 45baf4c..f4611fdb 100644 --- a/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc +++ b/third_party/blink/renderer/modules/peerconnection/adapters/p2p_quic_transport_factory_impl.cc
@@ -194,8 +194,23 @@ packet_writer->InitializeWithQuicConnection(quic_connection.get()); // QUIC configurations for the session are specified here. + // TODO(shampson): Consider setting larger initial flow control window sizes + // so that the default limit doesn't cause initial undersending. quic::QuicConfig quic_config; quic_config.SetMaxIncomingDynamicStreamsToSend(kMaxIncomingDynamicStreams); + // The handshake network timeouts are configured to large values to prevent + // the QUIC connection from being closed on a slow connection. This can occur + // if signaling is slow and one side begins the handshake early. + // See ICE related bug: bugs.webrtc.org/9869. + // + // This timeout is from time of creation of the quic::QuicConnection object to + // the completion of the handshake. It must be larger than the idle time. + quic_config.set_max_time_before_crypto_handshake( + quic::QuicTime::Delta::FromSeconds(50)); + // This is the timeout for idle time in the handshake. This value allows + // time for slow signaling to complete. + quic_config.set_max_idle_time_before_crypto_handshake( + quic::QuicTime::Delta::FromSeconds(30)); return std::make_unique<P2PQuicTransportImpl>( delegate, packet_transport, std::move(config), std::move(helper), std::move(quic_connection), quic_config, clock_);
diff --git a/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc b/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc index 4be645fb..c671a2a 100644 --- a/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc +++ b/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query.cc
@@ -49,7 +49,7 @@ GLboolean EXTDisjointTimerQuery::isQueryEXT(WebGLTimerQueryEXT* query) { WebGLExtensionScopedContext scoped(this); - if (!query || scoped.IsLost() || query->IsDeleted() || + if (!query || scoped.IsLost() || query->MarkedForDeletion() || !query->Validate(nullptr, scoped.Context())) { return false; } @@ -63,12 +63,8 @@ if (scoped.IsLost()) return; - DCHECK(query); - if (query->IsDeleted() || !query->Validate(nullptr, scoped.Context())) { - scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, "beginQueryEXT", - "invalid query"); + if (!scoped.Context()->ValidateWebGLObject("beginQueryEXT", query)) return; - } if (target != GL_TIME_ELAPSED_EXT) { scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "beginQueryEXT", @@ -121,12 +117,8 @@ if (scoped.IsLost()) return; - DCHECK(query); - if (query->IsDeleted() || !query->Validate(nullptr, scoped.Context())) { - scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, "queryCounterEXT", - "invalid query"); + if (!scoped.Context()->ValidateWebGLObject("queryCounterEXT", query)) return; - } if (target != GL_TIMESTAMP_EXT) { scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "queryCounterEXT", @@ -186,11 +178,12 @@ if (scoped.IsLost()) return ScriptValue::CreateNull(script_state); - DCHECK(query); - if (query->IsDeleted() || !query->Validate(nullptr, scoped.Context()) || - current_elapsed_query_ == query) { - scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, - "getQueryObjectEXT", "invalid query"); + if (!scoped.Context()->ValidateWebGLObject("getQueryObjectEXT", query)) + return ScriptValue::CreateNull(script_state); + + if (current_elapsed_query_ == query) { + scoped.Context()->SynthesizeGLError( + GL_INVALID_OPERATION, "getQueryObjectEXT", "query is currently active"); return ScriptValue::CreateNull(script_state); }
diff --git a/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc b/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc index 8eba91c..7e94d11 100644 --- a/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc +++ b/third_party/blink/renderer/modules/webgl/ext_disjoint_timer_query_webgl2.cc
@@ -37,13 +37,8 @@ if (scoped.IsLost()) return; - DCHECK(query); - if (query->IsDeleted() || - !query->Validate(scoped.Context()->ContextGroup(), scoped.Context())) { - scoped.Context()->SynthesizeGLError(GL_INVALID_OPERATION, "queryCounterEXT", - "invalid query"); + if (!scoped.Context()->ValidateWebGLObject("queryCounterEXT", query)) return; - } if (target != GL_TIMESTAMP_EXT) { scoped.Context()->SynthesizeGLError(GL_INVALID_ENUM, "queryCounterEXT",
diff --git a/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc b/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc index 359498a..bdb1fd9 100644 --- a/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc +++ b/third_party/blink/renderer/modules/webgl/oes_vertex_array_object.cc
@@ -77,6 +77,8 @@ if (!array_object->HasEverBeenBound()) return 0; + if (array_object->MarkedForDeletion()) + return 0; return scoped.Context()->ContextGL()->IsVertexArrayOES( array_object->Object()); @@ -88,12 +90,9 @@ if (scoped.IsLost()) return; - if (array_object && (array_object->IsDeleted() || - !array_object->Validate(nullptr, scoped.Context()))) { - scoped.Context()->SynthesizeGLError( - GL_INVALID_OPERATION, "bindVertexArrayOES", "invalid arrayObject"); + if (!scoped.Context()->ValidateNullableWebGLObject( + "OESVertexArrayObject.bindVertexArrayOES", array_object)) return; - } if (array_object && !array_object->IsDefaultObject() && array_object->Object()) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc index 25ece46..66d8748a 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.cc
@@ -43,8 +43,8 @@ // TODO(kainino): Change outByteLength to GLuint and change the associated // range checking (and all uses) - overflow becomes possible in cases below bool ValidateSubSourceAndGetData(DOMArrayBufferView* view, - GLuint sub_offset, - GLuint sub_length, + long long sub_offset, + long long sub_length, void** out_base_address, long long* out_byte_length) { // This is guaranteed to be non-null by DOM. @@ -245,7 +245,8 @@ "srcOffset + length too large"); return; } - BufferDataImpl(target, sub_byte_length, sub_base_address, usage); + BufferDataImpl(target, static_cast<GLsizeiptr>(sub_byte_length), + sub_base_address, usage); } void WebGL2RenderingContextBase::bufferData(GLenum target, @@ -269,7 +270,7 @@ void WebGL2RenderingContextBase::bufferSubData( GLenum target, - GLintptr dst_byte_offset, + long long dst_byte_offset, MaybeShared<DOMArrayBufferView> src_data, GLuint src_offset, GLuint length) { @@ -283,7 +284,8 @@ "srcOffset + length too large"); return; } - BufferSubDataImpl(target, dst_byte_offset, sub_byte_length, sub_base_address); + BufferSubDataImpl(target, dst_byte_offset, + static_cast<GLsizeiptr>(sub_byte_length), sub_base_address); } void WebGL2RenderingContextBase::bufferSubData(GLenum target, @@ -373,13 +375,14 @@ } void* mapped_data = ContextGL()->MapBufferRange( - target, static_cast<GLintptr>(src_byte_offset), destination_byte_length, - GL_MAP_READ_BIT); + target, static_cast<GLintptr>(src_byte_offset), + static_cast<GLsizeiptr>(destination_byte_length), GL_MAP_READ_BIT); if (!mapped_data) return; - memcpy(destination_data_ptr, mapped_data, destination_byte_length); + memcpy(destination_data_ptr, mapped_data, + static_cast<size_t>(destination_byte_length)); ContextGL()->UnmapBuffer(target); } @@ -439,14 +442,11 @@ WebGLTexture* texture, GLint level, GLint layer) { - if (isContextLost() || !ValidateFramebufferFuncParameters( - "framebufferTextureLayer", target, attachment)) + if (isContextLost() || + !ValidateFramebufferFuncParameters("framebufferTextureLayer", target, + attachment) || + !ValidateNullableWebGLObject("framebufferTextureLayer", texture)) return; - if (texture && !texture->Validate(ContextGroup(), this)) { - SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTextureLayer", - "texture does not belong to this context"); - return; - } GLenum textarget = texture ? texture->GetTarget() : 0; if (texture) { if (textarget != GL_TEXTURE_3D && textarget != GL_TEXTURE_2D_ARRAY) { @@ -1060,7 +1060,7 @@ GLint border, GLenum format, GLenum type, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!ValidateTexture2DBinding("texImage2D", target)) @@ -1096,7 +1096,7 @@ GLsizei height, GLenum format, GLenum type, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!ValidateTexture2DBinding("texSubImage2D", target)) @@ -1745,7 +1745,7 @@ GLint border, GLenum format, GLenum type, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!ValidateTexture3DBinding("texImage3D", target)) @@ -1942,7 +1942,7 @@ GLsizei depth, GLenum format, GLenum type, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!ValidateTexture3DBinding("texSubImage3D", target)) @@ -2197,7 +2197,7 @@ GLsizei height, GLint border, GLsizei image_size, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!bound_pixel_unpack_buffer_) { @@ -2279,7 +2279,7 @@ GLsizei height, GLenum format, GLsizei image_size, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!bound_pixel_unpack_buffer_) { @@ -2341,7 +2341,7 @@ GLsizei depth, GLint border, GLsizei image_size, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!bound_pixel_unpack_buffer_) { @@ -2407,7 +2407,7 @@ GLsizei depth, GLenum format, GLsizei image_size, - GLintptr offset) { + long long offset) { if (isContextLost()) return; if (!bound_pixel_unpack_buffer_) { @@ -2422,7 +2422,7 @@ GLint WebGL2RenderingContextBase::getFragDataLocation(WebGLProgram* program, const String& name) { - if (isContextLost() || !ValidateWebGLObject("getFragDataLocation", program)) + if (!ValidateWebGLProgramOrShader("getFragDataLocation", program)) return -1; return ContextGL()->GetFragDataLocation(ObjectOrZero(program), @@ -3817,22 +3817,18 @@ } GLboolean WebGL2RenderingContextBase::isQuery(WebGLQuery* query) { - if (isContextLost() || !query) + if (!query || isContextLost() || !query->Validate(ContextGroup(), this)) + return 0; + + if (query->MarkedForDeletion()) return 0; return ContextGL()->IsQueryEXT(query->Object()); } void WebGL2RenderingContextBase::beginQuery(GLenum target, WebGLQuery* query) { - bool deleted; - DCHECK(query); - if (!CheckObjectToBeBound("beginQuery", query, deleted)) + if (!ValidateWebGLObject("beginQuery", query)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "beginQuery", - "attempted to begin a deleted query object"); - return; - } if (query->GetTarget() && query->GetTarget() != target) { SynthesizeGLError(GL_INVALID_OPERATION, "beginQuery", @@ -3986,15 +3982,8 @@ ScriptState* script_state, WebGLQuery* query, GLenum pname) { - DCHECK(query); - bool deleted; - if (!CheckObjectToBeBound("getQueryParameter", query, deleted)) + if (!ValidateWebGLObject("getQueryParameter", query)) return ScriptValue::CreateNull(script_state); - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "getQueryParameter", - "attempted to access to a deleted query object"); - return ScriptValue::CreateNull(script_state); - } // Query is non-null at this point. if (!query->GetTarget()) { @@ -4048,7 +4037,10 @@ } GLboolean WebGL2RenderingContextBase::isSampler(WebGLSampler* sampler) { - if (isContextLost() || !sampler) + if (!sampler || isContextLost() || !sampler->Validate(ContextGroup(), this)) + return 0; + + if (sampler->MarkedForDeletion()) return 0; return ContextGL()->IsSampler(sampler->Object()); @@ -4056,14 +4048,8 @@ void WebGL2RenderingContextBase::bindSampler(GLuint unit, WebGLSampler* sampler) { - bool deleted; - if (!CheckObjectToBeBound("bindSampler", sampler, deleted)) + if (!ValidateNullableWebGLObject("bindSampler", sampler)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindSampler", - "attempted to bind a deleted sampler"); - return; - } if (unit >= sampler_units_.size()) { SynthesizeGLError(GL_INVALID_VALUE, "bindSampler", @@ -4081,7 +4067,7 @@ GLfloat paramf, GLint parami, bool is_float) { - if (isContextLost() || !ValidateWebGLObject("samplerParameter", sampler)) + if (!ValidateWebGLObject("samplerParameter", sampler)) return; GLint param; @@ -4191,7 +4177,7 @@ ScriptState* script_state, WebGLSampler* sampler, GLenum pname) { - if (isContextLost() || !ValidateWebGLObject("getSamplerParameter", sampler)) + if (!ValidateWebGLObject("getSamplerParameter", sampler)) return ScriptValue::CreateNull(script_state); switch (pname) { @@ -4237,7 +4223,10 @@ } GLboolean WebGL2RenderingContextBase::isSync(WebGLSync* sync) { - if (isContextLost() || !sync || !sync->Validate(ContextGroup(), this)) + if (!sync || isContextLost() || !sync->Validate(ContextGroup(), this)) + return 0; + + if (sync->MarkedForDeletion()) return 0; return sync->Object() != 0; @@ -4250,7 +4239,7 @@ GLenum WebGL2RenderingContextBase::clientWaitSync(WebGLSync* sync, GLbitfield flags, GLuint64 timeout) { - if (isContextLost() || !ValidateWebGLObject("clientWaitSync", sync)) + if (!ValidateWebGLObject("clientWaitSync", sync)) return GL_WAIT_FAILED; if (timeout > kMaxClientWaitTimeout) { @@ -4283,7 +4272,7 @@ void WebGL2RenderingContextBase::waitSync(WebGLSync* sync, GLbitfield flags, GLint64 timeout) { - if (isContextLost() || !ValidateWebGLObject("waitSync", sync)) + if (!ValidateWebGLObject("waitSync", sync)) return; if (flags) { @@ -4303,7 +4292,7 @@ ScriptState* script_state, WebGLSync* sync, GLenum pname) { - if (isContextLost() || !ValidateWebGLObject("getSyncParameter", sync)) + if (!ValidateWebGLObject("getSyncParameter", sync)) return ScriptValue::CreateNull(script_state); switch (pname) { @@ -4330,34 +4319,44 @@ void WebGL2RenderingContextBase::deleteTransformFeedback( WebGLTransformFeedback* feedback) { + // We have to short-circuit the deletion process if the transform feedback is + // active. This requires duplication of some validation logic. + if (!isContextLost() && feedback && + feedback->Validate(ContextGroup(), this)) { + if (feedback->active()) { + SynthesizeGLError( + GL_INVALID_OPERATION, "deleteTransformFeedback", + "attempt to delete an active transform feedback object"); + return; + } + } + + if (!DeleteObject(feedback)) + return; + if (feedback == transform_feedback_binding_) transform_feedback_binding_ = default_transform_feedback_; - - DeleteObject(feedback); } GLboolean WebGL2RenderingContextBase::isTransformFeedback( WebGLTransformFeedback* feedback) { - if (isContextLost() || !feedback || !feedback->Validate(ContextGroup(), this)) + if (!feedback || isContextLost() || !feedback->Validate(ContextGroup(), this)) return 0; if (!feedback->HasEverBeenBound()) return 0; + if (feedback->MarkedForDeletion()) + return 0; + return ContextGL()->IsTransformFeedback(feedback->Object()); } void WebGL2RenderingContextBase::bindTransformFeedback( GLenum target, WebGLTransformFeedback* feedback) { - bool deleted; - if (!CheckObjectToBeBound("bindTransformFeedback", feedback, deleted)) + if (!ValidateNullableWebGLObject("bindTransformFeedback", feedback)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindTransformFeedback", - "attempted to bind a deleted transform feedback object"); - return; - } if (target != GL_TRANSFORM_FEEDBACK) { SynthesizeGLError(GL_INVALID_ENUM, "bindTransformFeedback", @@ -4443,8 +4442,7 @@ WebGLProgram* program, const Vector<String>& varyings, GLenum buffer_mode) { - if (isContextLost() || - !ValidateWebGLObject("transformFeedbackVaryings", program)) + if (!ValidateWebGLProgramOrShader("transformFeedbackVaryings", program)) return; switch (buffer_mode) { @@ -4482,8 +4480,7 @@ WebGLActiveInfo* WebGL2RenderingContextBase::getTransformFeedbackVarying( WebGLProgram* program, GLuint index) { - if (isContextLost() || - !ValidateWebGLObject("getTransformFeedbackVarying", program)) + if (!ValidateWebGLProgramOrShader("getTransformFeedbackVarying", program)) return nullptr; if (!program->LinkStatus(this)) { @@ -4600,14 +4597,8 @@ WebGLBuffer* buffer) { if (isContextLost()) return; - bool deleted; - if (!CheckObjectToBeBound("bindBufferBase", buffer, deleted)) + if (!ValidateNullableWebGLObject("bindBufferBase", buffer)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase", - "attempt to bind a deleted buffer"); - return; - } if (target == GL_TRANSFORM_FEEDBACK_BUFFER && transform_feedback_binding_->active()) { SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase", @@ -4628,14 +4619,8 @@ long long size) { if (isContextLost()) return; - bool deleted; - if (!CheckObjectToBeBound("bindBufferRange", buffer, deleted)) + if (!ValidateNullableWebGLObject("bindBufferRange", buffer)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferRange", - "attempt to bind a deleted buffer"); - return; - } if (target == GL_TRANSFORM_FEEDBACK_BUFFER && transform_feedback_binding_->active()) { SynthesizeGLError(GL_INVALID_OPERATION, "bindBufferBase", @@ -4742,7 +4727,7 @@ WebGLProgram* program, const Vector<String>& uniform_names) { Vector<GLuint> result; - if (isContextLost() || !ValidateWebGLObject("getUniformIndices", program)) + if (!ValidateWebGLProgramOrShader("getUniformIndices", program)) return result; Vector<CString> keep_alive; // Must keep these instances alive while looking @@ -4764,7 +4749,7 @@ WebGLProgram* program, const Vector<GLuint>& uniform_indices, GLenum pname) { - if (isContextLost() || !ValidateWebGLObject("getActiveUniforms", program)) + if (!ValidateWebGLProgramOrShader("getActiveUniforms", program)) return ScriptValue::CreateNull(script_state); enum ReturnType { kEnumType, kUnsignedIntType, kIntType, kBoolType }; @@ -4841,7 +4826,7 @@ GLuint WebGL2RenderingContextBase::getUniformBlockIndex( WebGLProgram* program, const String& uniform_block_name) { - if (isContextLost() || !ValidateWebGLObject("getUniformBlockIndex", program)) + if (!ValidateWebGLProgramOrShader("getUniformBlockIndex", program)) return 0; if (!ValidateString("getUniformBlockIndex", uniform_block_name)) return 0; @@ -4876,8 +4861,7 @@ WebGLProgram* program, GLuint uniform_block_index, GLenum pname) { - if (isContextLost() || - !ValidateWebGLObject("getActiveUniformBlockParameter", program)) + if (!ValidateWebGLProgramOrShader("getActiveUniformBlockParameter", program)) return ScriptValue::CreateNull(script_state); if (!ValidateUniformBlockIndex("getActiveUniformBlockParameter", program, @@ -4924,8 +4908,7 @@ String WebGL2RenderingContextBase::getActiveUniformBlockName( WebGLProgram* program, GLuint uniform_block_index) { - if (isContextLost() || - !ValidateWebGLObject("getActiveUniformBlockName", program)) + if (!ValidateWebGLProgramOrShader("getActiveUniformBlockName", program)) return String(); if (!ValidateUniformBlockIndex("getActiveUniformBlockName", program, @@ -4958,7 +4941,7 @@ WebGLProgram* program, GLuint uniform_block_index, GLuint uniform_block_binding) { - if (isContextLost() || !ValidateWebGLObject("uniformBlockBinding", program)) + if (!ValidateWebGLProgramOrShader("uniformBlockBinding", program)) return; if (!ValidateUniformBlockIndex("uniformBlockBinding", program, @@ -4979,8 +4962,16 @@ void WebGL2RenderingContextBase::deleteVertexArray( WebGLVertexArrayObject* vertex_array) { - if (isContextLost() || !vertex_array || - !ValidateWebGLObject("deleteVertexArray", vertex_array)) + // ValidateWebGLObject generates an error if the object has already been + // deleted, so we must replicate most of its checks here. + if (isContextLost() || !vertex_array) + return; + if (!vertex_array->Validate(ContextGroup(), this)) { + SynthesizeGLError(GL_INVALID_OPERATION, "deleteVertexArray", + "object does not belong to this context"); + return; + } + if (vertex_array->MarkedForDeletion()) return; if (!vertex_array->IsDefaultObject() && @@ -4998,20 +4989,16 @@ if (!vertex_array->HasEverBeenBound()) return 0; + if (vertex_array->MarkedForDeletion()) + return 0; return ContextGL()->IsVertexArrayOES(vertex_array->Object()); } void WebGL2RenderingContextBase::bindVertexArray( WebGLVertexArrayObject* vertex_array) { - bool deleted; - if (!CheckObjectToBeBound("bindVertexArray", vertex_array, deleted)) + if (!ValidateNullableWebGLObject("bindVertexArray", vertex_array)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindVertexArray", - "attempt to bind a deleted vertex array"); - return; - } if (vertex_array && !vertex_array->IsDefaultObject() && vertex_array->Object()) { @@ -5027,16 +5014,9 @@ void WebGL2RenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* buffer) { - bool deleted; - if (!CheckObjectToBeBound("bindFramebuffer", buffer, deleted)) + if (!ValidateNullableWebGLObject("bindFramebuffer", buffer)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindFramebuffer", - "attempt to bind a deleted framebuffer"); - return; - } - switch (target) { case GL_DRAW_FRAMEBUFFER: break; @@ -5992,7 +5972,7 @@ const char* WebGL2RenderingContextBase::ValidateGetBufferSubData( const char* function_name, GLenum target, - GLintptr source_byte_offset, + long long source_byte_offset, DOMArrayBufferView* destination_array_buffer_view, GLuint destination_offset, GLuint length,
diff --git a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h index f8e36e4..730aa33 100644 --- a/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl2_rendering_context_base.h
@@ -35,7 +35,7 @@ GLuint, GLuint); void bufferSubData(GLenum, - GLintptr, + long long offset, MaybeShared<DOMArrayBufferView>, GLuint, GLuint); @@ -98,7 +98,7 @@ GLint, GLenum, GLenum, - GLintptr); + long long); void texImage2D(GLenum, GLint, GLint, @@ -170,7 +170,7 @@ GLsizei, GLenum, GLenum, - GLintptr); + long long); void texSubImage2D(GLenum, GLint, GLint, @@ -395,7 +395,7 @@ GLint, GLenum, GLenum, - GLintptr); + long long); void texSubImage3D(GLenum, GLint, GLint, @@ -418,7 +418,7 @@ GLsizei, GLenum, GLenum, - GLintptr); + long long); void texSubImage3D(GLenum, GLint, GLint, @@ -559,7 +559,7 @@ GLsizei height, GLint border, GLsizei image_size, - GLintptr offset); + long long offset); void compressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, @@ -568,7 +568,7 @@ GLsizei height, GLenum format, GLsizei image_size, - GLintptr offset); + long long offset); void compressedTexImage3D(GLenum target, GLint level, GLenum internalformat, @@ -577,7 +577,7 @@ GLsizei depth, GLint border, GLsizei image_size, - GLintptr offset); + long long offset); void compressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, @@ -588,7 +588,7 @@ GLsizei depth, GLenum format, GLsizei image_size, - GLintptr offset); + long long offset); // Have to re-declare/re-define the following compressedTex{Sub}Image2D // functions from the base class. This is because the above @@ -1088,7 +1088,7 @@ const char* ValidateGetBufferSubData(const char* function_name, GLenum target, - GLintptr source_byte_offset, + long long source_byte_offset, DOMArrayBufferView*, GLuint destination_offset, GLuint length,
diff --git a/third_party/blink/renderer/modules/webgl/webgl_multiview.cc b/third_party/blink/renderer/modules/webgl/webgl_multiview.cc index 8e36180..0419e82 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_multiview.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_multiview.cc
@@ -33,13 +33,9 @@ WebGLExtensionScopedContext scoped(this); if (scoped.IsLost()) return; - if (texture && - !texture->Validate(scoped.Context()->ContextGroup(), scoped.Context())) { - scoped.Context()->SynthesizeGLError( - GL_INVALID_OPERATION, "framebufferTextureMultiviewWEBGL", - "texture does not belong to this context"); + if (!scoped.Context()->ValidateNullableWebGLObject( + "framebufferTextureMultiviewWEBGL", texture)) return; - } GLenum textarget = texture ? texture->GetTarget() : 0; if (texture) { if (textarget != GL_TEXTURE_2D_ARRAY) {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_object.cc b/third_party/blink/renderer/modules/webgl/webgl_object.cc index f89c52a..b3db68f 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_object.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_object.cc
@@ -32,7 +32,7 @@ WebGLObject::WebGLObject(WebGLRenderingContextBase* context) : cached_number_of_context_losses_(context->NumberOfContextLosses()), attachment_count_(0), - deleted_(false), + marked_for_deletion_(false), destruction_in_progress_(false) {} WebGLObject::~WebGLObject() = default; @@ -42,7 +42,7 @@ } void WebGLObject::DeleteObject(gpu::gles2::GLES2Interface* gl) { - deleted_ = true; + marked_for_deletion_ = true; if (!HasObject()) return; @@ -66,7 +66,7 @@ } void WebGLObject::Detach() { - attachment_count_ = 0; // Make sure OpenGL resource is deleted. + attachment_count_ = 0; // Make sure OpenGL resource is eventually deleted. } void WebGLObject::DetachAndDeleteObject() { @@ -92,7 +92,7 @@ void WebGLObject::OnDetached(gpu::gles2::GLES2Interface* gl) { if (attachment_count_) --attachment_count_; - if (deleted_) + if (marked_for_deletion_) DeleteObject(gl); }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_object.h b/third_party/blink/renderer/modules/webgl/webgl_object.h index 0fc06c6b..08f3ccb 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_object.h +++ b/third_party/blink/renderer/modules/webgl/webgl_object.h
@@ -75,10 +75,10 @@ void OnAttached() { ++attachment_count_; } void OnDetached(gpu::gles2::GLES2Interface*); - // This indicates whether the client side issue a delete call already, not - // whether the OpenGL resource is deleted. - // object()==0 indicates the OpenGL resource is deleted. - bool IsDeleted() { return deleted_; } + // This indicates whether the client side has already issued a delete call, + // not whether the OpenGL resource is deleted. Object()==0, or !HasObject(), + // indicates that the OpenGL resource has been deleted. + bool MarkedForDeletion() { return marked_for_deletion_; } // True if this object belongs to the group or context. virtual bool Validate(const WebGLContextGroup*, @@ -130,9 +130,11 @@ unsigned attachment_count_; - // Indicates whether the WebGL context's deletion function for this - // object (deleteBuffer, deleteTexture, etc.) has been called. - bool deleted_; + // Indicates whether the WebGL context's deletion function for this object + // (deleteBuffer, deleteTexture, etc.) has been called. It does *not* indicate + // whether the underlying OpenGL resource has been destroyed; !HasObject() + // indicates that. + bool marked_for_deletion_; // Indicates whether the destructor has been entered and we therefore // need to be careful in subclasses to not touch other on-heap objects.
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc index 0ed3994..5332c24 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1704,8 +1704,8 @@ void WebGLRenderingContextBase::attachShader(WebGLProgram* program, WebGLShader* shader) { - if (isContextLost() || !ValidateWebGLObject("attachShader", program) || - !ValidateWebGLObject("attachShader", shader)) + if (!ValidateWebGLProgramOrShader("attachShader", program) || + !ValidateWebGLProgramOrShader("attachShader", shader)) return; if (!program->AttachShader(shader)) { SynthesizeGLError(GL_INVALID_OPERATION, "attachShader", @@ -1719,7 +1719,7 @@ void WebGLRenderingContextBase::bindAttribLocation(WebGLProgram* program, GLuint index, const String& name) { - if (isContextLost() || !ValidateWebGLObject("bindAttribLocation", program)) + if (!ValidateWebGLObject("bindAttribLocation", program)) return; if (!ValidateLocationLength("bindAttribLocation", name)) return; @@ -1732,23 +1732,6 @@ name.Utf8().data()); } -bool WebGLRenderingContextBase::CheckObjectToBeBound(const char* function_name, - WebGLObject* object, - bool& deleted) { - deleted = false; - if (isContextLost()) - return false; - if (object) { - if (!object->Validate(ContextGroup(), this)) { - SynthesizeGLError(GL_INVALID_OPERATION, function_name, - "object not from this context"); - return false; - } - deleted = object->IsDeleted(); - } - return true; -} - bool WebGLRenderingContextBase::ValidateAndUpdateBufferBindTarget( const char* function_name, GLenum target, @@ -1781,14 +1764,8 @@ } void WebGLRenderingContextBase::bindBuffer(GLenum target, WebGLBuffer* buffer) { - bool deleted; - if (!CheckObjectToBeBound("bindBuffer", buffer, deleted)) + if (!ValidateNullableWebGLObject("bindBuffer", buffer)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindBuffer", - "attempt to bind a deleted buffer"); - return; - } if (!ValidateAndUpdateBufferBindTarget("bindBuffer", target, buffer)) return; ContextGL()->BindBuffer(target, ObjectOrZero(buffer)); @@ -1796,14 +1773,8 @@ void WebGLRenderingContextBase::bindFramebuffer(GLenum target, WebGLFramebuffer* buffer) { - bool deleted; - if (!CheckObjectToBeBound("bindFramebuffer", buffer, deleted)) + if (!ValidateNullableWebGLObject("bindFramebuffer", buffer)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindFramebuffer", - "attempt to bind a deleted framebuffer"); - return; - } if (target != GL_FRAMEBUFFER) { SynthesizeGLError(GL_INVALID_ENUM, "bindFramebuffer", "invalid target"); @@ -1816,14 +1787,8 @@ void WebGLRenderingContextBase::bindRenderbuffer( GLenum target, WebGLRenderbuffer* render_buffer) { - bool deleted; - if (!CheckObjectToBeBound("bindRenderbuffer", render_buffer, deleted)) + if (!ValidateNullableWebGLObject("bindRenderbuffer", render_buffer)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindRenderbuffer", - "attempt to bind a deleted renderbuffer"); - return; - } if (target != GL_RENDERBUFFER) { SynthesizeGLError(GL_INVALID_ENUM, "bindRenderbuffer", "invalid target"); return; @@ -1836,14 +1801,8 @@ void WebGLRenderingContextBase::bindTexture(GLenum target, WebGLTexture* texture) { - bool deleted; - if (!CheckObjectToBeBound("bindTexture", texture, deleted)) + if (!ValidateNullableWebGLObject("bindTexture", texture)) return; - if (deleted) { - SynthesizeGLError(GL_INVALID_OPERATION, "bindTexture", - "attempt to bind a deleted texture"); - return; - } if (texture && texture->GetTarget() && texture->GetTarget() != target) { SynthesizeGLError(GL_INVALID_OPERATION, "bindTexture", "textures can not be used with multiple targets"); @@ -2145,7 +2104,7 @@ } void WebGLRenderingContextBase::compileShader(WebGLShader* shader) { - if (isContextLost() || !ValidateWebGLObject("compileShader", shader)) + if (!ValidateWebGLProgramOrShader("compileShader", shader)) return; ContextGL()->CompileShader(ObjectOrZero(shader)); } @@ -2358,6 +2317,11 @@ "object does not belong to this context"); return false; } + if (object->MarkedForDeletion()) { + // This is specified to be a no-op, including skipping all unbinding from + // the context's attachment points that would otherwise happen. + return false; + } if (object->HasObject()) { // We need to pass in context here because we want // things in this context unbound. @@ -2481,8 +2445,8 @@ void WebGLRenderingContextBase::detachShader(WebGLProgram* program, WebGLShader* shader) { - if (isContextLost() || !ValidateWebGLObject("detachShader", program) || - !ValidateWebGLObject("detachShader", shader)) + if (!ValidateWebGLProgramOrShader("detachShader", program) || + !ValidateWebGLProgramOrShader("detachShader", shader)) return; if (!program->DetachShader(shader)) { SynthesizeGLError(GL_INVALID_OPERATION, "detachShader", @@ -2531,12 +2495,55 @@ return true; } +bool WebGLRenderingContextBase::ValidateNullableWebGLObject( + const char* function_name, + WebGLObject* object) { + if (isContextLost()) + return false; + if (!object) { + // This differs in behavior to ValidateWebGLObject; null objects are allowed + // in these entry points. + return true; + } + return ValidateWebGLObject(function_name, object); +} + bool WebGLRenderingContextBase::ValidateWebGLObject(const char* function_name, WebGLObject* object) { + if (isContextLost()) + return false; DCHECK(object); + if (object->MarkedForDeletion()) { + SynthesizeGLError(GL_INVALID_OPERATION, function_name, + "attempt to use a deleted object"); + return false; + } + if (!object->Validate(ContextGroup(), this)) { + SynthesizeGLError(GL_INVALID_OPERATION, function_name, + "object does not belong to this context"); + return false; + } + return true; +} + +bool WebGLRenderingContextBase::ValidateWebGLProgramOrShader( + const char* function_name, + WebGLObject* object) { + if (isContextLost()) + return false; + DCHECK(object); + // OpenGL ES 3.0.5 p. 45: + // "Commands that accept shader or program object names will generate the + // error INVALID_VALUE if the provided name is not the name of either a shader + // or program object and INVALID_OPERATION if the provided name identifies an + // object that is not the expected type." + // + // Programs and shaders also have slightly different lifetime rules than other + // objects in the API; they continue to be usable after being marked for + // deletion. if (!object->HasObject()) { SynthesizeGLError(GL_INVALID_VALUE, function_name, - "no object or object deleted"); + "attempt to use a deleted object"); return false; } if (!object->Validate(ContextGroup(), this)) { @@ -2678,10 +2685,11 @@ "invalid target"); return; } - if (buffer && (!buffer->HasEverBeenBound() || - !buffer->Validate(ContextGroup(), this))) { + if (!ValidateNullableWebGLObject("framebufferRenderbuffer", buffer)) + return; + if (buffer && (!buffer->HasEverBeenBound())) { SynthesizeGLError(GL_INVALID_OPERATION, "framebufferRenderbuffer", - "buffer never bound or buffer not from this context"); + "renderbuffer has never been bound"); return; } // Don't allow the default framebuffer to be mutated; all current @@ -2712,11 +2720,10 @@ if (isContextLost() || !ValidateFramebufferFuncParameters( "framebufferTexture2D", target, attachment)) return; - if (texture && !texture->Validate(ContextGroup(), this)) { - SynthesizeGLError(GL_INVALID_OPERATION, "framebufferTexture2D", - "no texture or texture not from this context"); + if (!ValidateNullableWebGLObject("framebufferTexture2D", texture)) return; - } + // TODO(crbug.com/919711): validate texture's target against textarget. + // Don't allow the default framebuffer to be mutated; all current // implementations use an FBO internally in place of the default // FBO. @@ -2754,7 +2761,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveAttrib( WebGLProgram* program, GLuint index) { - if (isContextLost() || !ValidateWebGLObject("getActiveAttrib", program)) + if (!ValidateWebGLProgramOrShader("getActiveAttrib", program)) return nullptr; GLuint program_id = ObjectNonZero(program); GLint max_name_length = -1; @@ -2784,7 +2791,7 @@ WebGLActiveInfo* WebGLRenderingContextBase::getActiveUniform( WebGLProgram* program, GLuint index) { - if (isContextLost() || !ValidateWebGLObject("getActiveUniform", program)) + if (!ValidateWebGLProgramOrShader("getActiveUniform", program)) return nullptr; GLuint program_id = ObjectNonZero(program); GLint max_name_length = -1; @@ -2813,7 +2820,7 @@ base::Optional<HeapVector<Member<WebGLShader>>> WebGLRenderingContextBase::getAttachedShaders(WebGLProgram* program) { - if (isContextLost() || !ValidateWebGLObject("getAttachedShaders", program)) + if (!ValidateWebGLProgramOrShader("getAttachedShaders", program)) return base::nullopt; HeapVector<Member<WebGLShader>> shader_objects; @@ -2829,7 +2836,7 @@ GLint WebGLRenderingContextBase::getAttribLocation(WebGLProgram* program, const String& name) { - if (isContextLost() || !ValidateWebGLObject("getAttribLocation", program)) + if (!ValidateWebGLProgramOrShader("getAttribLocation", program)) return -1; if (!ValidateLocationLength("getAttribLocation", name)) return -1; @@ -3385,13 +3392,14 @@ ScriptState* script_state, WebGLProgram* program, GLenum pname) { - if (isContextLost() || !ValidateWebGLObject("getProgramParameter", program)) + if (!ValidateWebGLProgramOrShader("getProgramParamter", program)) { return ScriptValue::CreateNull(script_state); + } GLint value = 0; switch (pname) { case GL_DELETE_STATUS: - return WebGLAny(script_state, program->IsDeleted()); + return WebGLAny(script_state, program->MarkedForDeletion()); case GL_VALIDATE_STATUS: ContextGL()->GetProgramiv(ObjectOrZero(program), pname, &value); return WebGLAny(script_state, static_cast<bool>(value)); @@ -3432,7 +3440,7 @@ } String WebGLRenderingContextBase::getProgramInfoLog(WebGLProgram* program) { - if (isContextLost() || !ValidateWebGLObject("getProgramInfoLog", program)) + if (!ValidateWebGLProgramOrShader("getProgramInfoLog", program)) return String(); GLStringQuery query(ContextGL()); return query.Run<GLStringQuery::ProgramInfoLog>(ObjectNonZero(program)); @@ -3489,12 +3497,13 @@ ScriptState* script_state, WebGLShader* shader, GLenum pname) { - if (isContextLost() || !ValidateWebGLObject("getShaderParameter", shader)) + if (!ValidateWebGLProgramOrShader("getShaderParameter", shader)) { return ScriptValue::CreateNull(script_state); + } GLint value = 0; switch (pname) { case GL_DELETE_STATUS: - return WebGLAny(script_state, shader->IsDeleted()); + return WebGLAny(script_state, shader->MarkedForDeletion()); case GL_COMPILE_STATUS: ContextGL()->GetShaderiv(ObjectOrZero(shader), pname, &value); return WebGLAny(script_state, static_cast<bool>(value)); @@ -3517,7 +3526,7 @@ } String WebGLRenderingContextBase::getShaderInfoLog(WebGLShader* shader) { - if (isContextLost() || !ValidateWebGLObject("getShaderInfoLog", shader)) + if (!ValidateWebGLProgramOrShader("getShaderInfoLog", shader)) return String(); GLStringQuery query(ContextGL()); return query.Run<GLStringQuery::ShaderInfoLog>(ObjectNonZero(shader)); @@ -3553,7 +3562,7 @@ } String WebGLRenderingContextBase::getShaderSource(WebGLShader* shader) { - if (isContextLost() || !ValidateWebGLObject("getShaderSource", shader)) + if (!ValidateWebGLProgramOrShader("getShaderSource", shader)) return String(); return EnsureNotNull(shader->Source()); } @@ -3616,7 +3625,7 @@ ScriptState* script_state, WebGLProgram* program, const WebGLUniformLocation* uniform_location) { - if (isContextLost() || !ValidateWebGLObject("getUniform", program)) + if (!ValidateWebGLProgramOrShader("getUniform", program)) return ScriptValue::CreateNull(script_state); DCHECK(uniform_location); if (uniform_location->Program() != program) { @@ -3886,7 +3895,7 @@ WebGLUniformLocation* WebGLRenderingContextBase::getUniformLocation( WebGLProgram* program, const String& name) { - if (isContextLost() || !ValidateWebGLObject("getUniformLocation", program)) + if (!ValidateWebGLProgramOrShader("getUniformLocation", program)) return nullptr; if (!ValidateLocationLength("getUniformLocation", name)) return nullptr; @@ -4022,7 +4031,7 @@ if (!buffer->HasEverBeenBound()) return 0; - if (buffer->IsDeleted()) + if (buffer->MarkedForDeletion()) return 0; return ContextGL()->IsBuffer(buffer->Object()); @@ -4048,7 +4057,7 @@ if (!framebuffer->HasEverBeenBound()) return 0; - if (framebuffer->IsDeleted()) + if (framebuffer->MarkedForDeletion()) return 0; return ContextGL()->IsFramebuffer(framebuffer->Object()); @@ -4058,6 +4067,10 @@ if (!program || isContextLost() || !program->Validate(ContextGroup(), this)) return 0; + // OpenGL ES special-cases the behavior of program objects; if they're deleted + // while attached to the current context state, glIsProgram is supposed to + // still return true. For this reason, MarkedForDeletion is not checked here. + return ContextGL()->IsProgram(program->Object()); } @@ -4069,7 +4082,7 @@ if (!renderbuffer->HasEverBeenBound()) return 0; - if (renderbuffer->IsDeleted()) + if (renderbuffer->MarkedForDeletion()) return 0; return ContextGL()->IsRenderbuffer(renderbuffer->Object()); @@ -4079,6 +4092,10 @@ if (!shader || isContextLost() || !shader->Validate(ContextGroup(), this)) return 0; + // OpenGL ES special-cases the behavior of shader objects; if they're deleted + // while attached to a program, glIsShader is supposed to still return true. + // For this reason, MarkedForDeletion is not checked here. + return ContextGL()->IsShader(shader->Object()); } @@ -4088,7 +4105,7 @@ if (!texture->HasEverBeenBound()) return 0; - if (texture->IsDeleted()) + if (texture->MarkedForDeletion()) return 0; return ContextGL()->IsTexture(texture->Object()); @@ -4101,7 +4118,7 @@ } void WebGLRenderingContextBase::linkProgram(WebGLProgram* program) { - if (isContextLost() || !ValidateWebGLObject("linkProgram", program)) + if (!ValidateWebGLProgramOrShader("linkProgram", program)) return; if (program->ActiveTransformFeedbackCount() > 0) { @@ -4446,7 +4463,7 @@ void WebGLRenderingContextBase::shaderSource(WebGLShader* shader, const String& string) { - if (isContextLost() || !ValidateWebGLObject("shaderSource", shader)) + if (!ValidateWebGLProgramOrShader("shaderSource", shader)) return; String string_without_comments = StripComments(string).Result(); // TODO(danakj): Make validateShaderSource reject characters > 255 (or utf16 @@ -6225,11 +6242,8 @@ } void WebGLRenderingContextBase::useProgram(WebGLProgram* program) { - bool deleted; - if (!CheckObjectToBeBound("useProgram", program, deleted)) + if (!ValidateNullableWebGLObject("useProgram", program)) return; - if (deleted) - program = nullptr; if (program && !program->LinkStatus(this)) { SynthesizeGLError(GL_INVALID_OPERATION, "useProgram", "program not valid"); return; @@ -6246,7 +6260,7 @@ } void WebGLRenderingContextBase::validateProgram(WebGLProgram* program) { - if (isContextLost() || !ValidateWebGLObject("validateProgram", program)) + if (!ValidateWebGLProgramOrShader("validateProgram", program)) return; ContextGL()->ValidateProgram(ObjectOrZero(program)); }
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h index 7b6d15a7..a77c320 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h +++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -688,7 +688,23 @@ // Check if each enabled vertex attribute is bound to a buffer. bool ValidateRenderingState(const char*); - bool ValidateWebGLObject(const char*, WebGLObject*); + // Helper function for APIs which can legally receive null objects, including + // the bind* calls (bindBuffer, bindTexture, etc.) and useProgram. Checks that + // the object belongs to this context and that it's not marked for deletion. + // Returns false if the caller should return without further processing. + // Performs a context loss check internally. + // This returns true for null WebGLObject arguments! + bool ValidateNullableWebGLObject(const char* function_name, WebGLObject*); + + // Validates the incoming WebGL object, which is assumed to be non-null. + // Checks that the object belongs to this context and that it's not marked for + // deletion. Performs a context loss check internally. + bool ValidateWebGLObject(const char* function_name, WebGLObject*); + + // Validates the incoming WebGL program or shader, which is assumed to be + // non-null. OpenGL ES's validation rules differ for these types of objetcts + // compared to others. Performs a context loss check internally. + bool ValidateWebGLProgramOrShader(const char* function_name, WebGLObject*); // Adds a compressed texture format. void AddCompressedTextureFormat(GLenum); @@ -1496,13 +1512,6 @@ // Return false if caller should return without further processing. bool DeleteObject(WebGLObject*); - // Helper function for bind* (bindBuffer, bindTexture, etc) and useProgram. - // If the object has already been deleted, set deleted to true upon return. - // Return false if caller should return without further processing. - bool CheckObjectToBeBound(const char* function_name, - WebGLObject*, - bool& deleted); - void DispatchContextLostEvent(TimerBase*); // Helper for restoration after context lost. void MaybeRestoreContext(TimerBase*);
diff --git a/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc b/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc index 316d989c..2024fbf 100644 --- a/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc +++ b/third_party/blink/renderer/modules/webgl/webgl_shared_platform_3d_object.cc
@@ -13,9 +13,10 @@ : WebGLSharedObject(ctx), object_(0) {} void WebGLSharedPlatform3DObject::SetObject(GLuint object) { - // object==0 && deleted==false indicating an uninitialized state; + // SetObject may only be called when this container is in the + // uninitialized state: object==0 && marked_for_deletion==false. DCHECK(!object_); - DCHECK(!IsDeleted()); + DCHECK(!MarkedForDeletion()); object_ = object; }
diff --git a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h index 1106cd9..7b3cb90 100644 --- a/third_party/blink/renderer/platform/loader/fetch/fetch_context.h +++ b/third_party/blink/renderer/platform/loader/fetch/fetch_context.h
@@ -247,16 +247,6 @@ return task_runner_; } - // TODO(altimin): This is used when creating a URLLoader, and - // FetchContext::GetLoadingTaskRunner is used whenever asynchronous tasks - // around resource loading are posted. Modify the code so that all - // the tasks related to loading a resource use the resource loader handle's - // task runner. - virtual std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle> - CreateResourceLoadingTaskRunnerHandle() { - return nullptr; - } - // Called when the underlying context is detached. Note that some // FetchContexts continue working after detached (e.g., for fetch() operations // with "keepalive" specified).
diff --git a/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h b/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h index 8ba84ca..6f8f648 100644 --- a/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h +++ b/third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h
@@ -115,7 +115,9 @@ } WrappedResourceRequest wrapped(request); return url_loader_factory_->CreateURLLoader( - wrapped, CreateResourceLoadingTaskRunnerHandle()); + wrapped, + scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized( + GetLoadingTaskRunner())); } ResourceLoadScheduler::ThrottlingPolicy InitialLoadThrottlingPolicy() @@ -127,12 +129,6 @@ return frame_scheduler_.get(); } - std::unique_ptr<blink::scheduler::WebResourceLoadingTaskRunnerHandle> - CreateResourceLoadingTaskRunnerHandle() override { - return scheduler::WebResourceLoadingTaskRunnerHandle::CreateUnprioritized( - GetLoadingTaskRunner()); - } - private: class MockFrameScheduler final : public scheduler::FakeFrameScheduler { public:
diff --git a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG index f8b0236..f77a636 100644 --- a/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/blink/web_tests/FlagExpectations/enable-blink-features=LayoutNG
@@ -60,10 +60,10 @@ crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/hori-block-size-small-or-larger-than-container-with-min-or-max-content-2b.html [ Pass ] crbug.com/591099 external/wpt/css/vendor-imports/mozilla/mozilla-central-reftests/sizing/vert-block-size-small-or-larger-than-container-with-min-or-max-content-2a.html [ Pass ] +crbug.com/613663 external/wpt/quirks/table-cell-width-calculation.html [ Pass ] # New failures are appended below by the script. crbug.com/728378 compositing/culling/tile-occlusion-boundaries.html [ Failure ] -crbug.com/591099 compositing/overflow/border-radius-above-composited-subframe.html [ Failure ] crbug.com/591099 css3/filters/backdrop-filter-rendering.html [ Pass ] crbug.com/591099 css3/filters/composited-layer-child-bounds-after-composited-to-sw-shadow-change.html [ Failure ] crbug.com/591099 css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Failure ] @@ -199,10 +199,6 @@ crbug.com/591099 external/wpt/css/css-writing-modes/line-box-height-vlr-023.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/ortho-htb-alongside-vrl-floats-006.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/ortho-htb-alongside-vrl-floats-014.xht [ Pass ] -crbug.com/591099 external/wpt/css/css-writing-modes/orthogonal-parent-shrink-to-fit-001q.html [ Failure ] -crbug.com/591099 external/wpt/css/css-writing-modes/orthogonal-parent-shrink-to-fit-001r.html [ Failure ] -crbug.com/591099 external/wpt/css/css-writing-modes/orthogonal-parent-shrink-to-fit-001s.html [ Failure ] -crbug.com/591099 external/wpt/css/css-writing-modes/orthogonal-parent-shrink-to-fit-001t.html [ Failure ] crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-htb-in-vlr-001.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-prct-vrl-in-htb-001.xht [ Pass ] crbug.com/591099 external/wpt/css/css-writing-modes/sizing-orthog-vrl-in-htb-001.xht [ Pass ] @@ -318,7 +314,7 @@ crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/select-text-overflow-ellipsis-mixed-in-rtl.html [ Crash ] crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/select-text-overflow-ellipsis.html [ Crash ] crbug.com/591099 virtual/bidi-caret-affinity/editing/selection/word-granularity.html [ Crash ] -crbug.com/916511 virtual/composite-after-paint/paint/background/scrolling-background-with-negative-z-child.html [ Failure ] +crbug.com/916511 virtual/composite-after-paint/paint/background/scrolling-background-with-negative-z-child.html [ Failure Crash ] crbug.com/591099 virtual/composite-after-paint/paint/invalidation/box/margin.html [ Failure Pass ] crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/acquire-update-measure-remove.html [ Failure ] crbug.com/591099 virtual/display-lock/display-lock/lock-before-append/measure-forced-layout.html [ Failure ]
diff --git a/third_party/blink/web_tests/PRESUBMIT.py b/third_party/blink/web_tests/PRESUBMIT.py index c527a4dd..39cb587 100644 --- a/third_party/blink/web_tests/PRESUBMIT.py +++ b/third_party/blink/web_tests/PRESUBMIT.py
@@ -24,7 +24,7 @@ return [] checker_path = input_api.os_path.join(input_api.PresubmitLocalPath(), - '..', '..', 'blink', 'tools', 'check_testharness_expected_pass.py') + '..', 'tools', 'check_testharness_expected_pass.py') args = [input_api.python_executable, checker_path] args.extend(baseline_files) @@ -75,7 +75,7 @@ def _CheckTestExpectations(input_api, output_api): lint_path = input_api.os_path.join(input_api.PresubmitLocalPath(), - '..', '..', 'blink', 'tools', 'lint_test_expectations.py') + '..', 'tools', 'lint_test_expectations.py') _, errs = input_api.subprocess.Popen( [input_api.python_executable, lint_path], stdout=input_api.subprocess.PIPE, @@ -125,6 +125,22 @@ results.append(output_api.PresubmitError('Found an invalid preference %s in expected result %s:%s' % (error.group(1), f, line_num))) return results +def _CheckRunAfterLayoutAndPaintJS(input_api, output_api): + """Checks if resources/run-after-layout-and-paint.js and + http/tests/resources/run-after-layout-and-paint.js are the same.""" + js_file = input_api.os_path.join(input_api.PresubmitLocalPath(), + 'resources', 'run-after-layout-and-paint.js') + http_tests_js_file = input_api.os_path.join(input_api.PresubmitLocalPath(), + 'http', 'tests', 'resources', 'run-after-layout-and-paint.js') + for f in input_api.AffectedFiles(): + path = f.AbsoluteLocalPath() + if path == js_file or path == http_tests_js_file: + if not filecmp.cmp(js_file, http_tests_js_file): + return [output_api.PresubmitError( + '%s and %s must be kept exactly the same' % + (js_file, http_tests_js_file))] + break + return [] def CheckChangeOnUpload(input_api, output_api): results = [] @@ -133,6 +149,7 @@ results.extend(_CheckTestExpectations(input_api, output_api)) results.extend(_CheckForJSTest(input_api, output_api)) results.extend(_CheckForInvalidPreferenceError(input_api, output_api)) + results.extend(_CheckRunAfterLayoutAndPaintJS(input_api, output_api)) return results
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 480c7f9f..9793aa5b 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -394,10 +394,6 @@ crbug.com/882975 virtual/threaded/fast/events/pinch/scroll-visual-viewport-send-boundary-events.html [ Failure Pass ] ### See crbug.com/891427 comment near the top of this file: ###crbug.com/882975 virtual/threaded/synthetic_gestures/synthetic-pinch-zoom-gesture-touchscreen-desktop.html [ Failure Pass ] -crbug.com/911664 fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ] -crbug.com/911664 virtual/scroll_customization/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ] -crbug.com/911664 virtual/user-activation-v2/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ] -crbug.com/911664 virtual/mouseevent_fractional/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll.html [ Failure ] crbug.com/882973 http/tests/devtools/layers/layer-tree-model.js [ Failure ] crbug.com/884239 virtual/threaded/animations/animationworklet/worklet-animation-local-time-undefined.html [ Failure ] # Subpixel rounding differences that are incorrect. @@ -1525,10 +1521,8 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-auto-size.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/columns-height-set-via-top-bottom.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/content-height-with-scrollbars.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/crash-removing-out-of-flow-child.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/cross-axis-scrollbar.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/display-flexbox-set-get.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-baseline.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-baseline.html [ Crash ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-column.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-end.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-align-vertical-writing-mode.html [ Failure ] @@ -1538,48 +1532,36 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-auto-margins-no-available-space.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-auto-margins.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-border.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-margins-auto-size.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-margins-auto-size.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-margins.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-orientations.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-overflow.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow-padding.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-flow.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-item-contains-strict.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-one-sets-flex-basis-to-zero-px.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flex-order.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline-margins.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-height-with-overflow-auto.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-ignore-firstLetter.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline-margins.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-baseline.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-height-with-overflow-auto.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-lines-must-be-stretched-by-default.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-overflow-auto.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexbox-width-with-overflow-auto.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/flexitem.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/float-inside-flexitem.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/floated-flexbox.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-ignore-firstLine.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-wrap-vertically-width-calculation.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/intrinsic-min-width-applies-with-fixed-width.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/intrinsic-width-orthogonal-writing-mode.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/line-wrapping.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/min-size-auto.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/inline-flexbox-wrap-vertically-width-calculation.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/line-wrapping.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/min-size-auto.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/minimum-size-image.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-align-content-horizontal-column.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-align-self.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-align-self.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-column-auto.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-column-overflow.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-justify-content.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-justify-content.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-min-max.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-min-preferred-width.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-reverse-wrap-baseline.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-reverse-wrap-overflow.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-shrink-to-fit.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/negative-flex-rounding-assert.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline-shrink-to-fit.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/multiline.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/negative-overflow.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/nested-stretch.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/order-painting.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/orthogonal-flex-directions.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/orthogonal-writing-modes-and-intrinsic-sizing.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-and-padding.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/overflow-auto-resizes-correctly.html [ Failure ] @@ -1587,14 +1569,14 @@ crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-height-replaced-element.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-heights.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/percentage-sizes-quirks.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/position-absolute-child.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths-orthogonal.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/position-absolute-child.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths-orthogonal.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/preferred-widths.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-align-items.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relayout-image-load.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/relpos-with-percentage-top.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/scrollbars-auto.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/scrollbars.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/scrollbars-auto.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/scrollbars.html [ Crash ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/stretch-input-in-column.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/stretched-child-shrink-on-relayout.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/css3/flexbox/stretching-orthogonal-flows.html [ Failure ] @@ -1614,7 +1596,7 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-004.htm [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-005.htm [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-006.htm [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-001.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-002.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-003.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/align-content-wrap-004.html [ Failure ] @@ -1632,19 +1614,15 @@ crbug.com/807497 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-005.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/anonymous-flex-item-006.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/auto-margins-001.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap-reverse.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse-wrap.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-reverse.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap-reverse.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column-wrap.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-column.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse-wrap-reverse.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-reverse.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row-wrap-reverse.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-row.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/css-flexbox-test1.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/display_inline-flex_exist.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-align-items-center.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-align-items-center.html [ Failure ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-aspect-ratio-img-column-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-002.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-aspect-ratio-img-row-003.html [ Failure ] @@ -1658,8 +1636,8 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-010.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-011.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-flow-012.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-items-flexibility.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-margin-no-collapse.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-items-flexibility.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-margin-no-collapse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-001.xht [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-002.xht [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-003.xht [ Failure ] @@ -1715,30 +1693,28 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-wrap-reverse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-column-wrap.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_flow-row-wrap-reverse.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline-abspos.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline-float.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline-abspos.html [ Failure ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_inline.html [ Failure ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_justifycontent-center-overflow.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_margin-collapse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_order-box.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_order.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_quirks_body.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-direction.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-flow-reverse.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-flow.html [ Skip ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-order.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-direction.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-flow-reverse.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-flow.html [ Crash ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_rtl-order.html [ Crash ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_stf-table-singleline-2.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_stf-table-singleline.html [ Failure ] crbug.com/336604 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_visibility-collapse-line-wrapping.html [ Failure ] crbug.com/336604 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_visibility-collapse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flexbox_wrap-reverse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/layout-algorithm_algo-cross-line-002.html [ Failure ] -crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/negative-margins-001.html [ Skip ] +crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/negative-margins-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/order_value.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-000.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-002.html [ Failure ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-003.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-004.html [ Skip ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-001.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-002.html [ Failure ] @@ -1749,7 +1725,7 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-align-content-space-between.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-direction-column-reverse.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-direction-column.html [ Failure ] -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-inline.html [ Skip ] +crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-inline.html [ Failure ] crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-order.html [ Failure ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/ttwf-reftest-flex-wrap-reverse.html [ Failure ] @@ -1759,7 +1735,6 @@ crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-lines/multi-line-wrap-with-column-reverse.html [ Failure ] ### virtual/layout_ng_experimental/external/wpt/css/css-flexbox/getcomputedstyle/ -crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_display-inline.html [ Skip ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-basis-0percent.html [ Failure ] crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/getcomputedstyle/flexbox_computedstyle_flex-shorthand-number.html [ Failure ]
diff --git a/third_party/blink/web_tests/accessibility/animation-policy.html b/third_party/blink/web_tests/accessibility/animation-policy.html index 64c6f7e..f4bbb08 100644 --- a/third_party/blink/web_tests/accessibility/animation-policy.html +++ b/third_party/blink/web_tests/accessibility/animation-policy.html
@@ -1,3 +1,4 @@ +<script src="../resources/run-after-layout-and-paint.js"></script> <script> var updated = false; var prevTime; @@ -12,11 +13,6 @@ updated = true; } -function finishTest() { - if (window.testRunner) - testRunner.notifyDone(); -} - function imageLoaded() { if (!updated) return; @@ -24,11 +20,8 @@ } function onTimeout() { - if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function () { - window.requestAnimationFrame(finishTest); - }); - } + if (window.testRunner) + testRunner.notifyDone(); } </script> <body onload="changeImage()">
diff --git a/third_party/blink/web_tests/bluetooth/requestDevice/device-iframe.https.html b/third_party/blink/web_tests/bluetooth/requestDevice/device-iframe.https.html new file mode 100644 index 0000000..3885941 --- /dev/null +++ b/third_party/blink/web_tests/bluetooth/requestDevice/device-iframe.https.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script> +<body></body> +<script> +'use strict'; + +function createIframe(iframe) { + return new Promise(resolve => { + iframe.src = ''; + iframe.onload = () => { + resolve(iframe.contentWindow.navigator.bluetooth); + }; + document.body.appendChild(iframe); + }); +} + +promise_test(async(t) => { + let iframe = document.createElement('iframe'); + let iframeBluetoothObject = await createIframe(iframe); + document.body.removeChild(iframe); + // Set iframe to null to ensure that the GC cleans up as much as possible. + iframe = null; + GCController.collect(); + return callWithTrustedClick(iframeBluetoothObject.requestDevice) + .catch(err => assert_equals(err.name, 'ReferenceError')); + }, 'detaching from iframe invalidates reference to the iframe bluetooth object'); +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/bluetooth/requestLEScan/scan-iframe.https.html b/third_party/blink/web_tests/bluetooth/requestLEScan/scan-iframe.https.html new file mode 100644 index 0000000..2a5c01b1 --- /dev/null +++ b/third_party/blink/web_tests/bluetooth/requestLEScan/scan-iframe.https.html
@@ -0,0 +1,29 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../external/wpt/bluetooth/resources/bluetooth-helpers.js"></script> +<body></body> +<script> +'use strict'; + +function createIframe(iframe) { + return new Promise(resolve => { + iframe.src = ''; + iframe.onload = () => { + resolve(iframe.contentWindow.navigator.bluetooth); + }; + document.body.appendChild(iframe); + }); +} + +promise_test(async(t) => { + let iframe = document.createElement('iframe'); + let iframeBluetoothObject = await createIframe(iframe); + document.body.removeChild(iframe); + // Set iframe to null to ensure that the GC cleans up as much as possible. + iframe = null; + GCController.collect(); + return callWithTrustedClick(iframeBluetoothObject.requestLEScan) + .catch(err => assert_equals(err.name, 'ReferenceError')); + }, 'detaching from iframe invalidates reference to the iframe bluetooth object'); +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/css3/filters/background-image-blur-repaint.html b/third_party/blink/web_tests/css3/filters/background-image-blur-repaint.html index 8e2f89b..696d0bb 100644 --- a/third_party/blink/web_tests/css3/filters/background-image-blur-repaint.html +++ b/third_party/blink/web_tests/css3/filters/background-image-blur-repaint.html
@@ -3,24 +3,15 @@ <!-- You should see a 50x50 green box over a blurred background, with no white 100x100 box bleeding into the background image.--> <html> <head> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> - if (window.testRunner) - testRunner.waitUntilDone(); - function runTest() { function shrinkBox() { var box = document.getElementsByClassName("box")[0]; box.style.width = "50px"; box.style.height = "50px"; - if (window.testRunner) { - testRunner.notifyDone(); - } } - if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(shrinkBox); - } else { - setTimeout(shrinkBox, 500); - } + runAfterLayoutAndPaint(shrinkBox, true); } </script> <style>
diff --git a/third_party/blink/web_tests/editing/caret/caret_affinity_mouse_perturbation.html b/third_party/blink/web_tests/editing/caret/caret_affinity_mouse_perturbation.html new file mode 100644 index 0000000..0342afb --- /dev/null +++ b/third_party/blink/web_tests/editing/caret/caret_affinity_mouse_perturbation.html
@@ -0,0 +1,62 @@ +<!DOCTYPE html> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../assert_selection.js"></script> +<script> +const kStyle = ` +<style> +div.test { + font: 10px/10px Ahem; + width: 30px; + word-break: break-all; + padding-right: 10px; +} +</style>`; + +// Regression tests for https://crbug.com/919146 + +// Mouse down at the end of the first line. Without releasing, slightly move +// the mouse around. Caret shouldn't be moved to the second line. +selection_test( + `${kStyle}<div class="test" contenteditable>foobar</div>`, + selection => { + assert_own_property(window, 'eventSender'); + assert_own_property(window, 'internals'); + + const div = selection.document.querySelector('div.test'); + const x = selection.computeLeft(div) + 35; + const y = selection.computeTop(div) + 5; + eventSender.mouseMoveTo(x - 3, y); + eventSender.mouseDown(); + eventSender.mouseMoveTo(x + 3, y); + eventSender.mouseUp(); + + assert_equals(internals.textAffinity, 'Upstream'); + }, + `${kStyle}<div class="test" contenteditable>foo|bar</div>`, + 'Drag with upstream caret'); + +// Set upstream caret at the end of the first line. Then shift+click around the +// caret. Caret should remain upstream at the end of the first line. +selection_test( + `${kStyle}<div class="test" contenteditable>foobar</div>`, + selection => { + assert_own_property(window, 'eventSender'); + assert_own_property(window, 'internals'); + + const div = selection.document.querySelector('div.test'); + const x = selection.computeLeft(div) + 35; + const y = selection.computeTop(div) + 5; + eventSender.mouseMoveTo(x - 3, y); + eventSender.mouseDown(); + eventSender.mouseUp(); + + eventSender.mouseMoveTo(x + 3, y); + eventSender.mouseDown(0, ['shiftKey']); + eventSender.mouseUp(0, ['shiftKey']); + + assert_equals(internals.textAffinity, 'Upstream'); + }, + `${kStyle}<div class="test" contenteditable>foo|bar</div>`, + 'Shift+Click around upstream caret'); +</script>
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json index e1b7622..1aef400 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_5.json
@@ -51835,6 +51835,18 @@ {} ] ], + "css/css-masking/clip-path/clip-path-fixed-nested.html": [ + [ + "/css/css-masking/clip-path/clip-path-fixed-nested.html", + [ + [ + "/css/css-masking/clip-path/clip-path-fixed-nested-ref.html", + "==" + ] + ], + {} + ] + ], "css/css-masking/clip-path/clip-path-inline-001.html": [ [ "/css/css-masking/clip-path/clip-path-inline-001.html", @@ -137924,6 +137936,11 @@ {} ] ], + "css/css-masking/clip-path/clip-path-fixed-nested-ref.html": [ + [ + {} + ] + ], "css/css-masking/clip-path/reference/clip-path-circle-2-ref.html": [ [ {} @@ -166799,6 +166816,11 @@ {} ] ], + "html/rendering/non-replaced-elements/tables/table-attribute-expected.txt": [ + [ + {} + ] + ], "html/rendering/non-replaced-elements/tables/table-border-1-ref.html": [ [ {} @@ -236229,6 +236251,12 @@ {} ] ], + "html/rendering/non-replaced-elements/tables/table-attribute.html": [ + [ + "/html/rendering/non-replaced-elements/tables/table-attribute.html", + {} + ] + ], "html/rendering/non-replaced-elements/tables/table-vspace-hspace-s.html": [ [ "/html/rendering/non-replaced-elements/tables/table-vspace-hspace-s.html", @@ -276553,6 +276581,12 @@ {} ] ], + "svg/animations/scripted/end-element-on-inactive-element.svg": [ + [ + "/svg/animations/scripted/end-element-on-inactive-element.svg", + {} + ] + ], "svg/extensibility/foreignObject/containing-block.html": [ [ "/svg/extensibility/foreignObject/containing-block.html", @@ -346852,6 +346886,14 @@ "5806e75d536cc34a4610630782e5cdfd4b5e552d", "reftest" ], + "css/css-masking/clip-path/clip-path-fixed-nested-ref.html": [ + "b860304f04fe22498eb5b43d9de00d7e261353bb", + "support" + ], + "css/css-masking/clip-path/clip-path-fixed-nested.html": [ + "5090bc2aed43e0619eb7b966c2ed46cd43057e40", + "reftest" + ], "css/css-masking/clip-path/clip-path-inline-001.html": [ "21acae0ee7e06da76a6b5830e5aaa6b5e0d2e6a6", "reftest" @@ -402768,6 +402810,14 @@ "f06c3dc9b4f101faa253b8b1d980510475894992", "testharness" ], + "html/rendering/non-replaced-elements/tables/table-attribute-expected.txt": [ + "d5a1fc32f10bab297a27a8d557737452b3e6718b", + "support" + ], + "html/rendering/non-replaced-elements/tables/table-attribute.html": [ + "54acff0350eaee7fced7869c566bfb780b26cfd0", + "testharness" + ], "html/rendering/non-replaced-elements/tables/table-border-1-ref.html": [ "ceac88e9a3c82013165b1a64e7acd3d3841271fb", "support" @@ -443556,6 +443606,10 @@ "ee86b537ae987483687cc8ba6181db82f99ab162", "support" ], + "svg/animations/scripted/end-element-on-inactive-element.svg": [ + "34be9b9781f707d488e284c3285b82009557366b", + "testharness" + ], "svg/coordinate-systems/abspos.html": [ "fb37bbe7f3ae4a61d1c216970c8a263673aed0dc", "reftest"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-image-first-line.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-image-first-line.html new file mode 100644 index 0000000..c8dee70 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/background-image-first-line.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<title>CSS Test: background-image applicability to ::first-letter</title> +<link rel="help" href="http://www.w3.org/TR/css3-background/"> +<link rel="help" href="http://www.w3.org/TR/CSS21/selector.html#first-line-pseudo"> +<link rel="match" href="reference/background-image-first-line-ref.html"> +<meta name="flags" content="ahem image"> +<meta name="assert" content="background-image applicability to ::first-line"> +<style type="text/css"> +#content { + color: transparent; + font: 100px Ahem; +} +#content::first-line { + background-image: url("support/cat.png"); /* 98 w. by 99px h. */ + background-repeat: no-repeat; +} +</style> +<p>Test passes if cat image is visible.</p> +<div id="content">X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/background-image-first-line-ref.html b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/background-image-first-line-ref.html new file mode 100644 index 0000000..82fd9a2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-backgrounds/reference/background-image-first-line-ref.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta name="flags" content="ahem image"> +<style type="text/css"> +#content { + color: transparent; + font: 100px Ahem; + background-image: url("../support/cat.png"); /* 98 w. by 99px h. */ + background-repeat: no-repeat; +} +</style> +<p>Test passes if cat image is visible.</p> +<div id="content">X</div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-fixed-nested-ref.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-fixed-nested-ref.html new file mode 100644 index 0000000..b860304f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-fixed-nested-ref.html
@@ -0,0 +1,17 @@ +<!doctype html> +<title>CSS Test Reference</title> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<style> + body, html { + margin: 0; + padding: 0; + background: green; + } + + .purple-square { + background: purple; + width: 50px; + height: 50px; + } +</style> +<div class="purple-square"></div>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-fixed-nested.html b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-fixed-nested.html new file mode 100644 index 0000000..5090bc2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-masking/clip-path/clip-path-fixed-nested.html
@@ -0,0 +1,38 @@ +<!doctype html> +<title>CSS Test: nested clip-path() inside the same reference frame with position: fixed</title> +<link rel="author" href="mailto:emilio@crisal.io" title="Emilio Cobos Álvarez"> +<link rel="author" href="https://mozilla.org" title="Mozilla"> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1501111"> +<link rel="help" href="https://drafts.fxtf.org/css-masking/#the-clip-path"> +<link rel="match" href="clip-path-fixed-nested-ref.html"> +<style> + body, html { + margin: 0; + padding: 0; + } + .outer-clip { + height: 100vh; + clip-path: inset(0 0 0 0); + background: green; + } + .fixed { + position: fixed; + } + .inner-clip { + height: 50px; + width: 50px; + clip-path: inset(0 0 0 0); + } + .inner-clip-contents { + height: 100px; + width: 100px; + background: purple; + } +</style> +<div class="outer-clip"> + <div class="fixed"> + <div class="inner-clip"> + <div class="inner-clip-contents"></div> + </div> + </div> +</div>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html index 65c5b84..223a0a3 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/corb/img-mime-types-coverage.tentative.sub.html
@@ -45,7 +45,12 @@ const get_url = (mime) => { // www1 is cross-origin, so the HTTP response is CORB-eligible --> - url = "http://{{domains[www1]}}:{{ports[http][0]}}" + // + // TODO(lukasza@chromium.org): Once https://crbug.com/888079 and + // https://crbug.com/891872 are fixed, we should use a cross-*origin* + // rather than cross-*site* URL below (e.g. s/hosts[alt]/domains/g). + // See also https://crbug.com/918660 for more context. + url = "http://{{hosts[alt][www1]}}:{{ports[http][0]}}" url = url + "/fetch/nosniff/resources/image.py" if (mime != null) { url += "?type=" + encodeURIComponent(mime)
diff --git a/third_party/blink/web_tests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html index 82adc47..46403b0 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/corb/img-png-mislabeled-as-html-nosniff.tentative.sub.html
@@ -7,5 +7,11 @@ <meta charset="utf-8"> <!-- Reference page uses same-origin resources, which are not CORB-eligible. --> <link rel="match" href="img-png-mislabeled-as-html-nosniff.tentative.sub-ref.html"> -<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> -<img src="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png"> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible + +TODO(lukasza@chromium.org): Once https://crbug.com/888079 and +https://crbug.com/891872 are fixed, we should use a cross-*origin* +rather than cross-*site* URL below (e.g. s/hosts[alt]/domains/g). +See also https://crbug.com/918660 for more context. +--> +<img src="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png">
diff --git a/third_party/blink/web_tests/external/wpt/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html index cea80f2..2fc93f8 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/corb/preload-image-png-mislabeled-as-html-nosniff.tentative.sub.html
@@ -17,8 +17,14 @@ }); </script> -<!-- www1 is cross-origin, so the HTTP response is CORB-eligible --> +<!-- www1 is cross-origin, so the HTTP response is CORB-eligible + +TODO(lukasza@chromium.org): Once https://crbug.com/888079 and +https://crbug.com/891872 are fixed, we should use a cross-*origin* +rather than cross-*site* URL below (e.g. s/hosts[alt]/domains/g). +See also https://crbug.com/918660 for more context. +--> <link rel="preload" as="image" onerror="window.preloadErrorEvent()" onload="window.preloadLoadEvent()" - href="http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png"> + href="http://{{hosts[alt][www1]}}:{{ports[http][0]}}/fetch/corb/resources/png-mislabeled-as-html-nosniff.png">
diff --git a/third_party/blink/web_tests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html index 8f4d767..407cef9 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/corb/script-html-correctly-labeled.tentative.sub.html
@@ -24,7 +24,12 @@ }); // www1 is cross-origin, so the HTTP response is CORB-eligible. - script.src = 'http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html'; + // + // TODO(lukasza@chromium.org): Once https://crbug.com/888079 and + // https://crbug.com/891872 are fixed, we should use a cross-*origin* + // rather than cross-*site* URL below (e.g. s/hosts[alt]/domains/g). + // See also https://crbug.com/918660 for more context. + script.src = 'http://{{hosts[alt][www1]}}:{{ports[http][0]}}/fetch/corb/resources/html-correctly-labeled.html'; document.body.appendChild(script) }, "CORB-blocked script has no syntax errors"); </script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html b/third_party/blink/web_tests/external/wpt/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html index cabc7b0..03924cd 100644 --- a/third_party/blink/web_tests/external/wpt/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html +++ b/third_party/blink/web_tests/external/wpt/fetch/corb/script-resource-with-json-parser-breaker.tentative.sub.html
@@ -68,7 +68,12 @@ }); // www1 is cross-origin, so the HTTP response is CORB-eligible. - var src_prefix = "http://{{domains[www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py"; + // + // TODO(lukasza@chromium.org): Once https://crbug.com/888079 and + // https://crbug.com/891872 are fixed, we should use a cross-*origin* + // rather than cross-*site* URL below (e.g. s/hosts[alt]/domains/g). + // See also https://crbug.com/918660 for more context. + var src_prefix = "http://{{hosts[alt][www1]}}:{{ports[http][0]}}/fetch/corb/resources/sniffable-resource.py"; script.src = src_prefix + "?type=" + mime_type + "&body=" + encodeURIComponent(body); document.body.appendChild(script) }, "CORB-blocks '" + mime_type + "' that starts with the following JSON parser breaker: " + body);
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-attribute-expected.txt b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-attribute-expected.txt new file mode 100644 index 0000000..d5a1fc3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-attribute-expected.txt
@@ -0,0 +1,62 @@ +This is a testharness.js-based test. +Found 58 tests; 34 PASS, 24 FAIL, 0 TIMEOUT, 0 NOTRUN. +PASS table bordercolor attribute is correct +PASS table cellspacing attribute is correct +PASS table background attribute is correct +PASS table bgcolor attribute is correct +PASS thead background attribute is correct +PASS thead bgcolor attribute is correct +PASS tbody background attribute is correct +PASS tbody bgcolor attribute is correct +PASS tfoot background attribute is correct +PASS tfoot bgcolor attribute is correct +PASS tr background attribute is correct +PASS tr bgcolor attribute is correct +PASS td background attribute is correct +PASS td bgcolor attribute is correct +PASS th background attribute is correct +PASS th bgcolor attribute is correct +FAIL table thead align attribute center is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table thead align attribute middle is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table thead align attribute left is correct assert_equals: expected "left" but got "-webkit-left" +FAIL table thead align attribute right is correct assert_equals: expected "right" but got "-webkit-right" +PASS table thead align attribute justify is correct +FAIL table tbody align attribute center is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table tbody align attribute middle is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table tbody align attribute left is correct assert_equals: expected "left" but got "-webkit-left" +FAIL table tbody align attribute right is correct assert_equals: expected "right" but got "-webkit-right" +PASS table tbody align attribute justify is correct +FAIL table tfoot align attribute center is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table tfoot align attribute middle is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table tfoot align attribute left is correct assert_equals: expected "left" but got "-webkit-left" +FAIL table tfoot align attribute right is correct assert_equals: expected "right" but got "-webkit-right" +PASS table tfoot align attribute justify is correct +FAIL table tr align attribute center is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table tr align attribute middle is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table tr align attribute left is correct assert_equals: expected "left" but got "-webkit-left" +FAIL table tr align attribute right is correct assert_equals: expected "right" but got "-webkit-right" +PASS table tr align attribute justify is correct +FAIL table td align attribute center is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table td align attribute middle is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table td align attribute left is correct assert_equals: expected "left" but got "-webkit-left" +FAIL table td align attribute right is correct assert_equals: expected "right" but got "-webkit-right" +PASS table td align attribute justify is correct +FAIL table th align attribute center is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table th align attribute middle is correct assert_equals: expected "center" but got "-webkit-center" +FAIL table th align attribute left is correct assert_equals: expected "left" but got "-webkit-left" +FAIL table th align attribute right is correct assert_equals: expected "right" but got "-webkit-right" +PASS table th align attribute justify is correct +PASS tr height attribute pixel is correct +PASS td height attribute pixel is correct +PASS th height attribute pixel is correct +PASS table_tr height attribute percentage is correct +PASS table_td height attribute percentage is correct +PASS table_th height attribute percentage is correct +PASS table height attribute pixel is correct +PASS table height attribute 90% is correct +PASS table height attribute 110% is correct +PASS table cellpadding attribute is correct +PASS th default align attribute is center +PASS table col width attribute is correct +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-attribute.html b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-attribute.html new file mode 100644 index 0000000..54acff0 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/non-replaced-elements/tables/table-attribute.html
@@ -0,0 +1,194 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Table attribute test</title> +<link rel="help" href="https://html.spec.whatwg.org/multipage/rendering.html#tables-2"> +<link rel="author" title="Intel" href="http://www.intel.com"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<style> + .div_tbl table { + width: 400px; + height: 300px; + border-spacing: 0px; + } + .div_tbl td { + padding: 0px; + } + .div_tbl th { + padding: 0px; + } + .div_200 { + height: 200px; + } +</style> + +<div id="div"> + <table id="table"> + <thead id="thead"> + <tr> + <th id="th">Month</th> + <th>Savings</th> + </tr> + </thead> + <tbody id="tbody"> + <tr id="tr"> + <td>January</td> + <td>$60</td> + </tr> + <tr> + <td id="td">February</td> + <td>$80</td> + </tr> + </tbody> + <tfoot id="tfoot"> + <tr> + <td>Sum</td> + <td>$140</td> + </tr> + </tfoot> + </table> +</div> + +<script> + +const ids = ["table", "thead", "tbody", "tfoot", "tr", "td", "th"]; +const alignIds = ["thead", "tbody", "tfoot", "tr", "td", "th"]; +const heightIds = ["tr", "td", "th"]; +const div = document.getElementById("div"); +const table = document.getElementById("table"); +const aligns = [ + ["center", "center"], + ["middle", "center"], + ["left", "left"], + ["right", "right"], + ["justify", "justify"] +]; + +function commonTest(id, attr, value, cssProp, expected) { + test(t => { + let elem = document.getElementById(id); + t.add_cleanup(() => { + elem.removeAttribute(attr); + }); + elem.setAttribute(attr, value); + let css = window.getComputedStyle(elem, null).getPropertyValue(cssProp); + assert_equals(css, expected); + }, `${id} ${attr} attribute is correct`); +} + +function commonAlignTest(id, attr, value, cssProp, expected) { + test(t => { + let elem = document.getElementById(id); + t.add_cleanup(() => { + elem.removeAttribute(attr); + }); + elem.setAttribute(attr, value); + let css = window.getComputedStyle(elem, null).getPropertyValue(cssProp); + assert_equals(css, expected); + }, `table ${id} align attribute ${value} is correct`); +} + +function commonHeightTest(id, attr, value, cssProp, expected, type="", divClass) { + test(t => { + let elem = document.getElementById(id); + t.add_cleanup(() => { + elem.removeAttribute(attr); + div.classList.remove(divClass); + }); + elem.setAttribute(attr, value); + div.classList.add(divClass); + let css = window.getComputedStyle(elem, null).getPropertyValue(cssProp); + assert_equals(css, expected); + }, `${id} ${attr} attribute ${type} is correct`); +} + +// table#bordercolor +commonTest("table", "bordercolor", "red", "border-color", "rgb(255, 0, 0)"); +// table#cellspacing +commonTest("table", "cellspacing", "10", "border-spacing", "10px 10px", "10"); + +// {table, thead, body, tfoot, tr, td, th}#background +// {table, thead, body, tfoot, tr, td, th}#bgcolor +const url = new URL('/images/threecolors.png', window.location.href).href; +for (let id of ids) { + commonTest(id, "background", "/images/threecolors.png", "background-image", `url(\"${url}\")`); + + commonTest(id, "bgcolor", "red", "background-color", "rgb(255, 0, 0)"); +} + +// {thead, body, tfoot, tr, td, th}#align#{center, middle, left, right, justify} +for (let id of alignIds) { + for (let [value, expected] of aligns) { + commonAlignTest(id, "align", value, "text-align", expected); + } +} + +// {tr, td, th}#height#pixel +for (let id of heightIds) { + commonHeightTest(id, "height", "60", "height", "60px", "pixel", "div_tbl"); +} + +// {tr, td, th}#height#percentage +let tbl = document.createElement("table"); +tbl.innerHTML = '<tr id="table_tr"><th id="table_th"></th></tr><tr><td id="table_td"></td></tr>'; +div.appendChild(tbl); +const heightPercIds = ["table_tr", "table_td", "table_th"]; +for (let id of heightPercIds) { + commonHeightTest(id, "height", "20%", "height", "60px", "percentage", "div_tbl"); +} +div.removeChild(tbl); + +// table#height#{pixel, percentage} +commonHeightTest("table", "height", "180", "height", "180px", "pixel", "div_200"); +commonHeightTest("table", "height", "90%", "height", "180px", "90%", "div_200"); +commonHeightTest("table", "height", "110%", "height", "220px", "110%", "div_200"); + +// table#cellpadding +test(t => { + t.add_cleanup(() => { + table.removeAttribute("cellpadding"); + }); + table.setAttribute("cellpadding", "10"); + + let th = document.getElementById("th"); + let th_css = window.getComputedStyle(th, null).getPropertyValue("padding"); + assert_equals(th_css, "10px"); + + let td = document.getElementById("td"); + let td_css = window.getComputedStyle(td, null).getPropertyValue("padding"); + assert_equals(td_css, "10px"); +}, "table cellpadding attribute is correct"); + +// th default text-align property is center +test(t => { + let elem = document.getElementById("th"); + let css = window.getComputedStyle(elem, null).getPropertyValue("text-align"); + assert_equals(css, "center"); +}, "th default align attribute is center"); + +// col#width#{pixel, percentage} +test(t => { + let colgroup = document.createElement("colgroup"); + let col1 = document.createElement("col"); + let col2 = document.createElement("col"); + t.add_cleanup(() => { + table.removeChild(colgroup); + div.classList.remove("div_tbl"); + }); + colgroup.appendChild(col1); + colgroup.appendChild(col2); + table.insertBefore(colgroup, table.firstChild); + div.classList.add("div_tbl"); + + col1.setAttribute("width", "100"); + let td = document.getElementById("td"); + let css = window.getComputedStyle(td, null).getPropertyValue("width"); + assert_equals(css, "100px"); + + col1.setAttribute("width", "50%"); + css = window.getComputedStyle(td, null).getPropertyValue("width"); + assert_equals(css, "200px"); +}, "table col width attribute is correct"); + +</script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-link-element/resources/link-style-error.js b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-link-element/resources/link-style-error.js index d1fa5ac..7ebc39b 100644 --- a/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-link-element/resources/link-style-error.js +++ b/third_party/blink/web_tests/external/wpt/html/semantics/document-metadata/the-link-element/resources/link-style-error.js
@@ -1,7 +1,13 @@ ["<link>", "@import"].forEach(linkType => { [ ["same-origin", "resources/css.py"], - ["cross-origin", get_host_info().HTTP_REMOTE_ORIGIN + "/html/semantics/document-metadata/the-link-element/resources/css.py"] + + // TODO(lukasza@chromium.org): Once https://crbug.com/888079 and + // https://crbug.com/891872 are fixed, we should use a cross-*origin* rather + // than cross-*site* URL below (e.g. s/ HTTP_NOTSAMESITE_ORIGIN / + // HTTP_REMOTE_ORIGIN /g). See also https://crbug.com/918660 for more + // context. + ["cross-origin", get_host_info().HTTP_NOTSAMESITE_ORIGIN + "/html/semantics/document-metadata/the-link-element/resources/css.py"] ].forEach(originType => { ["no Content-Type", "wrong Content-Type", "broken Content-Type"].forEach(contentType => { ["no nosniff", "nosniff"].forEach(nosniff => {
diff --git a/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background-rounded.html b/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background-rounded.html index b278082..a83fe4d1 100644 --- a/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background-rounded.html +++ b/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background-rounded.html
@@ -9,13 +9,14 @@ width: 200px; } </style> + <script src="../../resources/run-after-layout-and-paint.js"></script> <script type="text/javascript" charset="utf-8"> if (window.testRunner) testRunner.waitUntilDone(); function pageLoaded() { - testRunner.layoutAndPaintAsyncThen(function () { + runAfterLayoutAndPaint(function () { window.setTimeout(function() { if (window.testRunner) testRunner.notifyDone();
diff --git a/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background.html b/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background.html index 2868a08..d6054a1 100644 --- a/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background.html +++ b/third_party/blink/web_tests/fast/backgrounds/animated-gif-as-background.html
@@ -8,13 +8,14 @@ width: 200px; } </style> + <script src="../../resources/run-after-layout-and-paint.js"></script> <script type="text/javascript" charset="utf-8"> if (window.testRunner) testRunner.waitUntilDone(); function pageLoaded() { - testRunner.layoutAndPaintAsyncThen(function () { + runAfterLayoutAndPaint(function () { window.setTimeout(function() { if (window.testRunner) testRunner.notifyDone();
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-webgl.html b/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-webgl.html index 7508cebc..be7acb89 100644 --- a/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-webgl.html +++ b/third_party/blink/web_tests/fast/canvas/canvas-createImageBitmap-webgl.html
@@ -1,6 +1,7 @@ <html> <head> <script src="../../resources/js-test.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> </head> <body onload="start();"> <canvas id="webgl" width="200" height="200"></canvas> @@ -40,11 +41,7 @@ gl.clearColor(0.0, 1.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT); createImageBitmapAndCheck(webgl_canvas, false).then(function() { - if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(asyncTest); - } else { - window.requestAnimationFrame(asyncTest); - } + runAfterLayoutAndPaint(asyncTest); }); }
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-no-alpha-invalidation.html b/third_party/blink/web_tests/fast/canvas/canvas-no-alpha-invalidation.html index 0427b4c..7c101ff 100644 --- a/third_party/blink/web_tests/fast/canvas/canvas-no-alpha-invalidation.html +++ b/third_party/blink/web_tests/fast/canvas/canvas-no-alpha-invalidation.html
@@ -1,10 +1,11 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <p>Expect to see a black square below this line.</p> <canvas id = 'c' width='100' height='100'></canvas> <script> if (window.testRunner) { testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ // Verify that creating a context with alpha:false trigger a graphics // update even though nothing is drawn to the canvas. document.getElementById('c').getContext('2d', { alpha:false }); @@ -13,4 +14,4 @@ } else { console.log('ERROR: This test requires the testRunner interface.') } -</script> \ No newline at end of file +</script>
diff --git a/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d-after-to-data-url-without-context.html b/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d-after-to-data-url-without-context.html index 359649a..9bf67c2 100644 --- a/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d-after-to-data-url-without-context.html +++ b/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d-after-to-data-url-without-context.html
@@ -13,6 +13,7 @@ <canvas id="nonpreserve-canvas3d" width="100" height="100"></canvas> <canvas id="nonpreserve-canvas2d" width="100" height="100"></canvas> <script src="../../../resources/js-test.js"></script> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="resources/draw-webgl-to-canvas-2d.js"></script> <script> function createContexts() {
diff --git a/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d.html b/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d.html index 3b90d53..14cbfa3a 100644 --- a/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d.html +++ b/third_party/blink/web_tests/fast/canvas/webgl/draw-webgl-to-canvas-2d.html
@@ -27,6 +27,7 @@ <canvas id="nonpreserve-canvas3d" width="100" height="100"></canvas> <canvas id="nonpreserve-canvas2d" width="100" height="100"></canvas> <script src="../../../resources/js-test.js"></script> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="resources/draw-webgl-to-canvas-2d.js"></script> <script> function createContexts() {
diff --git a/third_party/blink/web_tests/fast/canvas/webgl/resources/draw-webgl-to-canvas-2d.js b/third_party/blink/web_tests/fast/canvas/webgl/resources/draw-webgl-to-canvas-2d.js index 28d2247..eddb57f3 100644 --- a/third_party/blink/web_tests/fast/canvas/webgl/resources/draw-webgl-to-canvas-2d.js +++ b/third_party/blink/web_tests/fast/canvas/webgl/resources/draw-webgl-to-canvas-2d.js
@@ -68,14 +68,9 @@ debug("2) when drawingBuffer is not preserved.") drawWebGLToCanvas2D(nonpreserve_ctx2D, nonpreserve_canvas3D, false); - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(asyncTest); - } else { - window.requestAnimationFrame(asyncTest); - } + runAfterLayoutAndPaint(asyncTest); } window.onload = function () { - window.requestAnimationFrame(startTestAfterFirstPaint); + runAfterLayoutAndPaint(startTestAfterFirstPaint); }
diff --git a/third_party/blink/web_tests/fast/deprecated-flexbox/stretch-align-svg.html b/third_party/blink/web_tests/fast/deprecated-flexbox/stretch-align-svg.html index 6cb1cdb4..9baa0aa4 100644 --- a/third_party/blink/web_tests/fast/deprecated-flexbox/stretch-align-svg.html +++ b/third_party/blink/web_tests/fast/deprecated-flexbox/stretch-align-svg.html
@@ -19,9 +19,6 @@ <div id="spanner"></div> </div> <script> -if (window.testRunner) - testRunner.waitUntilDone(); - runAfterLayoutAndPaint(function() { document.body.appendChild(document.createElement('div')); document.body.offsetLeft; @@ -29,8 +26,5 @@ var c = document.querySelector('rect'); c.setAttribute('height', '100%'); c.getScreenCTM(); - - if (window.testRunner) - testRunner.layoutAndPaintAsyncThen(function() { testRunner.notifyDone(); }); -}); +}, true); </script>
diff --git a/third_party/blink/web_tests/fast/events/middleClickAutoscroll-drag-scrollable-iframe-div.html b/third_party/blink/web_tests/fast/events/middleClickAutoscroll-drag-scrollable-iframe-div.html index a870a1e..49c4f19 100644 --- a/third_party/blink/web_tests/fast/events/middleClickAutoscroll-drag-scrollable-iframe-div.html +++ b/third_party/blink/web_tests/fast/events/middleClickAutoscroll-drag-scrollable-iframe-div.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <script src="../../resources/js-test.js"> </script> +<script src="../../resources/run-after-layout-and-paint.js"> </script> <script> var button_was_clicked = false; @@ -7,14 +8,14 @@ if (window.testRunner) { testRunner.waitUntilDone(); testRunner.dumpAsText(); - testRunner.layoutAndPaintAsyncThen( + runAfterLayoutAndPaint( function() { var iframe = document.getElementById('ScrollIFrame'); var iframeDocument = iframe.contentDocument; var textInIFrame = iframeDocument.getElementById('textInFrame'); if (window.eventSender) { debug("Starting Autoscroll test on iframe"); - testRunner.layoutAndPaintAsyncThen( + runAfterLayoutAndPaint( function() { var x = iframe.offsetLeft + textInIFrame.offsetLeft + 7; var y = iframe.offsetTop + textInIFrame.offsetTop + 7; @@ -23,7 +24,7 @@ eventSender.mouseDown(1); eventSender.mouseMoveTo(x + 220, y + 220); eventSender.mouseUp(1); - testRunner.layoutAndPaintAsyncThen(autoscrollTestPart2); + runAfterLayoutAndPaint(autoscrollTestPart2); }); } }); @@ -43,7 +44,7 @@ // This click actually clicks the button. eventSender.mouseDown(); eventSender.mouseUp(); - testRunner.runAfterLayoutAndPaint(checkButtonClicked); + runAfterLayoutAndPaint(checkButtonClicked); } function checkButtonClicked() { @@ -73,4 +74,4 @@ <button id="testCompletedButton" type="button" onclick="testCompleted()"> Click me </button> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/blink/web_tests/fast/events/middleClickAutoscroll-modal-scrollable-iframe-div.html b/third_party/blink/web_tests/fast/events/middleClickAutoscroll-modal-scrollable-iframe-div.html index bfcd0b1..ccb3b7a 100644 --- a/third_party/blink/web_tests/fast/events/middleClickAutoscroll-modal-scrollable-iframe-div.html +++ b/third_party/blink/web_tests/fast/events/middleClickAutoscroll-modal-scrollable-iframe-div.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <script src="../../resources/js-test.js"> </script> +<script src="../../resources/run-after-layout-and-paint.js"> </script> <script> var button_was_clicked = false; @@ -7,14 +8,14 @@ if (window.testRunner) { testRunner.waitUntilDone(); testRunner.dumpAsText(); - testRunner.layoutAndPaintAsyncThen( + runAfterLayoutAndPaint( function() { var iframe = document.getElementById('ScrollIFrame'); var iframeDocument = iframe.contentDocument; var textInIFrame = iframeDocument.getElementById('textInFrame'); if (window.eventSender) { debug("Starting Autoscroll test on iframe"); - testRunner.layoutAndPaintAsyncThen( + runAfterLayoutAndPaint( function() { var x = iframe.offsetLeft + textInIFrame.offsetLeft + 7; var y = iframe.offsetTop + textInIFrame.offsetTop + 7; @@ -23,7 +24,7 @@ eventSender.mouseDown(1); eventSender.mouseUp(1); eventSender.mouseMoveTo(x + 220, y + 220); - testRunner.layoutAndPaintAsyncThen(autoscrollTestPart2); + runAfterLayoutAndPaint(autoscrollTestPart2); }); } }); @@ -43,7 +44,7 @@ // This click actually clicks the button. eventSender.mouseDown(); eventSender.mouseUp(); - testRunner.runAfterLayoutAndPaint(checkButtonClicked); + runAfterLayoutAndPaint(checkButtonClicked); } function checkButtonClicked() { @@ -73,4 +74,4 @@ <button id="testCompletedButton" type="button" onclick="testCompleted()"> Click me </button> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt index 6df2158..ce49af64 100644 --- a/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt +++ b/third_party/blink/web_tests/fast/events/touch/compositor-touch-hit-rects-non-composited-scroll-expected.txt
@@ -13,7 +13,7 @@ divInsideNonScrollableLayer: layer(0,0 785x671) has hit test rect (14,273 273x10) -divInsideCompositedLayer: layer(0,10 273x22) has hit test rect (0,10 273x12) +divInsideCompositedLayer: layer(14,305 273x22) has hit test rect (0,10 273x12) overflowwithborder: layer(0,0 785x767) has hit test rect (13,336 290x50)
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-background-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-background-color.html index 1610463..1420316 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-background-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-background-color.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.keepWebHistory(); - testRunner.waitUntilDone(); -} </script> <style> a { background-color: red; text-decoration: none; color: initial } @@ -11,11 +10,8 @@ </style> <a id="anchor" href="">Should have a green background when hovered</a> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-border-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-border-color.html index 353aea7..a59611bd 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-border-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-border-color.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.keepWebHistory(); - testRunner.waitUntilDone(); -} </script> <style> a { border: solid red 10px; text-decoration: none; color: initial } @@ -11,11 +10,8 @@ </style> <a id="anchor" href="">Should have a green border when hovered</a> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 10, anchor.offsetTop + 10); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-emphasis-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-emphasis-color.html index 84077a6..368a40a0 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-emphasis-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-emphasis-color.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { - testRunner.keepWebHistory(); +if (window.testRunner) testRunner.waitUntilDone(); -} </script> <style> a { -webkit-text-emphasis-style: filled } @@ -15,11 +14,8 @@ <a id="anchor" href="">Emphasis should be green when hovered</a> </div> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-outline-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-outline-color.html index e748c1a6..d031640a 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-outline-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-outline-color.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.keepWebHistory(); - testRunner.waitUntilDone(); -} </script> <style> a { outline: solid red 10px; text-decoration: none; color: initial } @@ -11,11 +10,8 @@ </style> <a id="anchor" href="">Should have a green outline when hovered</a> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-text-decoration-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-text-decoration-color.html index 27f9f9a..969cd5a 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-text-decoration-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-text-decoration-color.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.keepWebHistory(); - testRunner.waitUntilDone(); -} </script> <style> div { text-decoration-color: red; } @@ -14,11 +13,8 @@ <a id="anchor" href="">Should be green (including underline) when hovered</a> </div> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-text-fill-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-text-fill-color.html index 8dd6e23f..fb3680a 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-text-fill-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-text-fill-color.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.keepWebHistory(); @@ -15,7 +16,7 @@ </div> <script> if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); testRunner.notifyDone();
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover-text-stroke-color.html b/third_party/blink/web_tests/fast/history/visited-link-hover-text-stroke-color.html index ca567cc..8794d32 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover-text-stroke-color.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover-text-stroke-color.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.keepWebHistory(); - testRunner.waitUntilDone(); -} </script> <style> div { -webkit-text-stroke-width: 1px; -webkit-text-stroke-color: red } @@ -14,11 +13,8 @@ <a id="anchor" href="">Should have green stroke when hovered</a> </div> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/history/visited-link-hover.html b/third_party/blink/web_tests/fast/history/visited-link-hover.html index 5e3053a..46af269 100644 --- a/third_party/blink/web_tests/fast/history/visited-link-hover.html +++ b/third_party/blink/web_tests/fast/history/visited-link-hover.html
@@ -1,9 +1,8 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.keepWebHistory(); - testRunner.waitUntilDone(); -} </script> <style> div { color: red; } @@ -14,11 +13,8 @@ <a id="anchor" href="">Should be green when hovered</a> </div> <script> -if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function(){ + runAfterLayoutAndPaint(function(){ if (window.eventSender); eventSender.mouseMoveTo(anchor.offsetLeft + 1, anchor.offsetTop + 1); - testRunner.notifyDone(); - }); -} + }, true); </script>
diff --git a/third_party/blink/web_tests/fast/layers/layer-status-change-crash.html b/third_party/blink/web_tests/fast/layers/layer-status-change-crash.html index 92719f6..0d4f312 100644 --- a/third_party/blink/web_tests/fast/layers/layer-status-change-crash.html +++ b/third_party/blink/web_tests/fast/layers/layer-status-change-crash.html
@@ -1,16 +1,17 @@ <!DOCTYPE HTML> <body> <div id="div">This test passes if it does not crash.</div> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.waitUntilDone(); testRunner.dumpAsText(); var div = document.getElementById('div'); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { div.style.position = 'relative'; div.style.backgroundColor = 'blue'; - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { div.textContent += ' PASS'; testRunner.notifyDone(); });
diff --git a/third_party/blink/web_tests/fast/layers/layer-visibility-sublayer.html b/third_party/blink/web_tests/fast/layers/layer-visibility-sublayer.html index 7209217..8de8f32 100644 --- a/third_party/blink/web_tests/fast/layers/layer-visibility-sublayer.html +++ b/third_party/blink/web_tests/fast/layers/layer-visibility-sublayer.html
@@ -8,18 +8,13 @@ .abstop { position: absolute; left:0; right:0; height:30px } .abs { position: absolute; left:0; right:0; top:0; bottom:0 } </style> - +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> var node1; var node2; function startTest() { - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(doTest) - } else { - requestAnimationFrame(doTest) - } + runAfterLayoutAndPaint(doTest, true); } function doTest() @@ -35,12 +30,6 @@ //26 document.getElementById('26c').style.setProperty('visibility','hidden',''); document.getElementById('26a').removeChild(document.getElementById('26b')); - - if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function() { - testRunner.notifyDone(); - }); - } }
diff --git a/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-animates.html b/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-animates.html index c90ccd6..7ada4dd 100644 --- a/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-animates.html +++ b/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-animates.html
@@ -15,6 +15,7 @@ </style> <script src="../../resources/js-test.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <div id="container"> <div id="content"></div> </div> @@ -32,7 +33,7 @@ element.addEventListener("scroll", onElementScroll); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { // Give the container focus. eventSender.mouseMoveTo(100, 100); eventSender.mouseDown();
diff --git a/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-precise-deltas-dont-animate.html b/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-precise-deltas-dont-animate.html index a71993b..4a17147 100644 --- a/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-precise-deltas-dont-animate.html +++ b/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-precise-deltas-dont-animate.html
@@ -15,6 +15,7 @@ </style> <script src="../../resources/js-test.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <div id="container"> <div id="content"></div> </div> @@ -32,7 +33,7 @@ element.addEventListener("scroll", onElementScroll); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { // Give the container focus. eventSender.mouseMoveTo(100, 100); eventSender.mouseScrollBy(0, -20, /* paged */ false,
diff --git a/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-root-frame-animates.html b/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-root-frame-animates.html index 2105aab..39aeffaf 100644 --- a/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-root-frame-animates.html +++ b/third_party/blink/web_tests/fast/scroll-behavior/overflow-scroll-root-frame-animates.html
@@ -7,6 +7,7 @@ } </style> <script src="../../resources/js-test.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <div id="content"></div> <div id="console"></div> <script> @@ -21,7 +22,7 @@ window.addEventListener("scroll", onWindowScroll); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { eventSender.keyDown('End'); }); }
diff --git a/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-local-background.html b/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-local-background.html index 188a4c1..14a1b0e 100644 --- a/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-local-background.html +++ b/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-local-background.html
@@ -16,17 +16,9 @@ <div id="container"> <div id="bloat"></div> </div> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function() { - document.getElementById('container').scrollTop = 1000; - testRunner.notifyDone(); - }); - } else { - // For manual test. - setTimeout(function() { - document.getElementById('container').scrollTop = 1000; - }, 500); - } +runAfterLayoutAndPaint(function() { + document.getElementById('container').scrollTop = 1000; +}, true); </script>
diff --git a/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-to-ancestor-backing.html b/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-to-ancestor-backing.html index caed95fe..5269e8e 100644 --- a/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-to-ancestor-backing.html +++ b/third_party/blink/web_tests/fast/scrolling/non-composited-scrolling-repaint-to-ancestor-backing.html
@@ -26,17 +26,9 @@ <div id="clipped"></div> </div> </div> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function() { - document.getElementById('container').scrollTop = 1000; - testRunner.notifyDone(); - }); - } else { - // For manual test. - setTimeout(function() { - document.getElementById('container').scrollTop = 1000; - }, 500); - } +runAfterLayoutAndPaint(function() { + document.getElementById('container').scrollTop = 1000; +}, true); </script>
diff --git a/third_party/blink/web_tests/fast/webgl/canvas-to-data-url.html b/third_party/blink/web_tests/fast/webgl/canvas-to-data-url.html index 63cdfaf5..2a66980 100644 --- a/third_party/blink/web_tests/fast/webgl/canvas-to-data-url.html +++ b/third_party/blink/web_tests/fast/webgl/canvas-to-data-url.html
@@ -4,6 +4,7 @@ <canvas id="preserve-canvas3d" width="10" height="10"></canvas> <canvas id="nonpreserve-canvas3d" width="10" height="10"></canvas> <script src="../../resources/js-test.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.dumpAsText(); @@ -44,12 +45,7 @@ debug("2) when drawingBuffer is not preserved.") shouldBeTrue("nonpreserve_canvas3D.toDataURL('image/png') == internals.getImageSourceURL(nonpreserve_canvas3D)"); - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(asyncTest); - } else { - window.requestAnimationFrame(asyncTest); - } + runAfterLayoutAndPaint(asyncTest); } window.onload = function () {
diff --git a/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-repaint.html b/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-repaint.html index 54a537f..a2b8cb3 100644 --- a/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-repaint.html +++ b/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-repaint.html
@@ -42,6 +42,7 @@ } </script> <script src="resources/webgl-test-utils.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> var ctxs = [] @@ -116,17 +117,9 @@ function repaintTest() { drawAll(50); - if (window.testRunner) { - testRunner.notifyDone(); - } } function runRepaintTest() { - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(repaintTest); - } else { - setTimeout(repaintTest, 100); - } + runAfterLayoutAndPaint(repaintTest, true); } </script>
diff --git a/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-tabswitching.html b/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-tabswitching.html index fc1eb58d..800295a 100644 --- a/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-tabswitching.html +++ b/third_party/blink/web_tests/fast/webgl/webgl-composite-modes-tabswitching.html
@@ -42,6 +42,7 @@ } </script> <script src="resources/webgl-test-utils.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> var ctxs = [] @@ -121,32 +122,27 @@ } } -function setPageVisible() { - if (window.testRunner) { - testRunner.setPageVisibility("visible"); - testRunner.layoutAndPaintAsyncThen(repaintOnVisiblePage); - } else { - setTimeout(repaintOnVisiblePage, 50); - } -} - function repaintOnHiddenPage() { if (window.testRunner) { testRunner.setPageVisibility("hidden"); } // Although page is hidden, WebGL must draw this frame. drawAll(30); - // testRunner.layoutAndPaintAsyncThen doesn't work when page is hidden. - setTimeout(setPageVisible, 50); + + // TODO(crbug.com/919536): Ideally this should be wrapped in + // runAfterLayoutAndPaint() to ensure test coverage, but for now that will + // crash. + if (window.testRunner) { + testRunner.setPageVisibility("visible"); + } + runAfterLayoutAndPaint(repaintOnVisiblePage); } function runRepaintTest() { drawAll(0); if (window.testRunner) { testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(repaintOnHiddenPage); - } else { - setTimeout(repaintOnHiddenPage, 50); } + runAfterLayoutAndPaint(repaintOnHiddenPage); } </script>
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt index 12127c1..78b2d92 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -21,6 +21,11 @@ "object": "InlineTextBox 'test test test'", "rect": [0, 0, 74, 16], "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [26, 0, 26, 16], + "reason": "selection" } ], "transform": 2
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt index d13cd0b0..09ad592 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -21,6 +21,11 @@ "object": "InlineTextBox 'test test test'", "rect": [0, 0, 74, 16], "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [26, 0, 26, 16], + "reason": "selection" } ], "transform": 2
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-inserted-listitem-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-inserted-listitem-expected.txt index 05cdce6..21b0436c 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-inserted-listitem-expected.txt +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-inserted-listitem-expected.txt
@@ -9,10 +9,20 @@ { "object": "LayoutSVGRect rect id='move'", "rect": [28, 38, 10, 10], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRect rect id='move'", + "rect": [28, 18, 10, 10], "reason": "chunk appeared" }, { "object": "LayoutSVGRect rect id='move'", + "rect": [28, 18, 10, 10], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRect rect id='move'", "rect": [18, 18, 10, 10], "reason": "disappeared" }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt index 1ba2fa3..779ace7 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt
@@ -12,11 +12,31 @@ "reason": "appeared" }, { + "object": "InlineTextBox ' B C'", + "rect": [23, 8, 85, 23], + "reason": "appeared" + }, + { + "object": "InlineTextBox ' B C'", + "rect": [23, 8, 85, 23], + "reason": "disappeared" + }, + { "object": "InlineTextBox 'A'", "rect": [23, 8, 85, 23], "reason": "appeared" }, { + "object": "InlineTextBox 'A'", + "rect": [23, 8, 85, 23], + "reason": "appeared" + }, + { + "object": "InlineTextBox 'A'", + "rect": [23, 8, 85, 23], + "reason": "disappeared" + }, + { "object": "InlineTextBox ' B C'", "rect": [23, 8, 80, 23], "reason": "disappeared"
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-expected.txt index 047e65c..4cb073e 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-expected.txt +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/modify-transferred-listitem-expected.txt
@@ -10,6 +10,11 @@ "object": "LayoutSVGPath polygon id='target'", "rect": [18, 18, 30, 20], "reason": "full" + }, + { + "object": "LayoutSVGPath polygon id='target'", + "rect": [18, 18, 20, 20], + "reason": "full" } ] }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt index d552b0c..b8d8eae 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=CompositeAfterPaint/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt
@@ -93,6 +93,16 @@ }, { "object": "LayoutBlockFlow (positioned) div id='html' class='outerBox'", + "rect": [415, 125, 150, 150], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow (positioned) div id='html' class='outerBox'", + "rect": [415, 125, 150, 150], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow (positioned) div id='html' class='outerBox'", "rect": [400, 100, 150, 150], "reason": "geometry" }, @@ -183,6 +193,16 @@ }, { "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [115, 125, 150, 150], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [115, 125, 150, 150], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", "rect": [100, 100, 150, 150], "reason": "paint property change" }, @@ -273,6 +293,16 @@ }, { "object": "LayoutBlockFlow div class='innerBox'", + "rect": [440, 150, 100, 100], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow div class='innerBox'", + "rect": [440, 150, 100, 100], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow div class='innerBox'", "rect": [425, 125, 100, 100], "reason": "geometry" }, @@ -363,6 +393,16 @@ }, { "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [140, 150, 100, 100], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [140, 150, 100, 100], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", "rect": [125, 125, 100, 100], "reason": "paint property change" }
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_elements_in_series-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_elements_in_series-expected.png index 918c197..bfb60b3 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_elements_in_series-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/css1/box_properties/float_elements_in_series-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/css/content/content-quotes-01-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/css/content/content-quotes-01-expected.txt new file mode 100644 index 0000000..7eb8ae2 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/css/content/content-quotes-01-expected.txt
@@ -0,0 +1,13 @@ +The texts between the markers should be identical. + +========Marker1======== + +ab 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + +========Marker2======== + +WWaWWbWWWWWWWW 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + +========Marker3======== + +PASSED
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/css/content/content-quotes-05-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/css/content/content-quotes-05-expected.txt new file mode 100644 index 0000000..e9c2297 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/css/content/content-quotes-05-expected.txt
@@ -0,0 +1,11 @@ +========Marker1======== + +abc 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + +========Marker2======== + +WWaWWWbWWWWWcWWWW 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + +========Marker3======== + +PASSED
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-big-endian-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-big-endian-expected.png index 701be09..fdc06b8 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-big-endian-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-big-endian-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-little-endian-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-little-endian-expected.png index 701be09..fdc06b8 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-little-endian-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/encoding/utf-16-little-endian-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/lists/ordered-list-with-no-ol-tag-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/lists/ordered-list-with-no-ol-tag-expected.png index ac07f77..67097f19 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/lists/ordered-list-with-no-ol-tag-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/lists/ordered-list-with-no-ol-tag-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-collapsed-border-expected.png index 6a0e191..b535785 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-collapsed-border-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-collapsed-border-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-expected.png index 6a0e191..b535785 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-opacity-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-collapsed-border-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-collapsed-border-expected.png index 8299aab8..af18a818 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-collapsed-border-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-collapsed-border-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-expected.png index a0c0b9f..2e5b6e7c 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/table/backgr_layers-show-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/007-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/007-expected.png index 4cf62d0..be271c6 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/007-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/basic/007-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/international/003-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/international/003-expected.png new file mode 100644 index 0000000..04dcf573 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/fast/text/international/003-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/html/tabular_data/td_colspan_rendering-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/html/tabular_data/td_colspan_rendering-expected.png index 3d1b89d4..1636877 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/html/tabular_data/td_colspan_rendering-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/html/tabular_data/td_colspan_rendering-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..334b04e --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -0,0 +1,44 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [800, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='target'", + "rect": [7, 7, 63, 24], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [10, 11, 57, 16], + "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [10, 11, 56, 16], + "reason": "selection" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [10, 11, 56, 16], + "reason": "paint property change" + } + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..91fc6664 --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,39 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [800, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='target'", + "rect": [7, 7, 63, 24], + "reason": "subtree" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [10, 11, 57, 16], + "reason": "selection" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [10, 11, 57, 16], + "reason": "paint property change" + } + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug106158-1-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug106158-1-expected.png index 0ade942b..51ca9ad 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug106158-1-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug106158-1-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug2267-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug2267-expected.png index 4af0433..abe95de 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug2267-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug2267-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug38916-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug38916-expected.png index 807a0a02..5c546b68 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug38916-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug38916-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug44523-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug44523-expected.png index dc336e9..b38d335 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug44523-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug44523-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-1-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-1-expected.png index 54f8a993..dda3d871 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-1-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-1-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-2-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-2-expected.png index 54f8a993..dda3d871 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-2-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-2-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-5-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-5-expected.png index 2f32213d..045f6118 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-5-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-5-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-expected.png index 2f32213d..045f6118 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46268-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-1-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-1-expected.png index 1a1f1c6..b261af6 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-1-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-1-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-2-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-2-expected.png index d1368bb..896f1c1 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-2-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug46480-2-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug57828-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug57828-expected.png index eb0a525..1049910 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug57828-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug57828-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug59354-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug59354-expected.png index a88c517..c918880 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug59354-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug59354-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug69382-2-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug69382-2-expected.png index 95ef6063..99a64ac 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug69382-2-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/bugs/bug69382-2-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/marvin/x_tbody_align_char-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/marvin/x_tbody_align_char-expected.png index 1d2addfb..c915189c 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/marvin/x_tbody_align_char-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla/marvin/x_tbody_align_char-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug32205-4-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug32205-4-expected.png index 557383c..24be6b6 100644 --- a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug32205-4-expected.png +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug32205-4-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug8499-expected.png b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug8499-expected.png new file mode 100644 index 0000000..42d26e6b --- /dev/null +++ b/third_party/blink/web_tests/flag-specific/enable-blink-features=LayoutNG/tables/mozilla_expected_failures/bugs/bug8499-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/fullscreen/enter-exit-full-screen-hover.html b/third_party/blink/web_tests/fullscreen/enter-exit-full-screen-hover.html index 47249365..141d6a2 100644 --- a/third_party/blink/web_tests/fullscreen/enter-exit-full-screen-hover.html +++ b/third_party/blink/web_tests/fullscreen/enter-exit-full-screen-hover.html
@@ -7,6 +7,7 @@ } </style> <script src="../resources/js-test.js"></script> +<script src="../resources/run-after-layout-and-paint.js"></script> <script src="full-screen-test.js"></script> <script src="../fast/events/touch/resources/touch-hover-active-tests.js"></script> <link rel="stylesheet" href="../fast/events/touch/resources/touch-hover-active-tests.css"> @@ -32,13 +33,13 @@ // After entering fullscreen + layout, the button should lose hover. waitForEventOnce(document, 'webkitfullscreenchange', function() { shouldBeTrue("document.webkitIsFullScreen"); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { shouldBeDefault("getHoverActiveState(enterButton)"); // After exiting fullscreen + layout, the button should lose hover. waitForEventOnce(document, 'webkitfullscreenchange', function() { shouldBeFalse("document.webkitIsFullScreen"); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { shouldBeDefault("getHoverActiveState(exitButton)"); endTest(); });
diff --git a/third_party/blink/web_tests/fullscreen/full-screen-stacking-context.html b/third_party/blink/web_tests/fullscreen/full-screen-stacking-context.html index 80f5c53..f01119ce 100644 --- a/third_party/blink/web_tests/fullscreen/full-screen-stacking-context.html +++ b/third_party/blink/web_tests/fullscreen/full-screen-stacking-context.html
@@ -1,12 +1,13 @@ <!DOCTYPE html> <html> <head> + <script src="../resources/run-after-layout-and-paint.js"></script> <script> var runPixelTests = true; function init() { waitForEventOnce(document, 'webkitfullscreenchange', function() { - testRunner.layoutAndPaintAsyncThen(endTest); + runAfterLayoutAndPaint(endTest); }); runWithKeyDown(goFullScreen); }
diff --git a/third_party/blink/web_tests/fullscreen/full-screen-test.js b/third_party/blink/web_tests/fullscreen/full-screen-test.js index 800322b..729dcb2b 100644 --- a/third_party/blink/web_tests/fullscreen/full-screen-test.js +++ b/third_party/blink/web_tests/fullscreen/full-screen-test.js
@@ -142,7 +142,7 @@ consoleWrite("END OF TEST"); testEnded = true; if (window.testRunner) - testRunner.layoutAndPaintAsyncThen(() => testRunner.notifyDone()); + testRunner.notifyDone(); } function logResult(success, text)
diff --git a/third_party/blink/web_tests/http/tests/csspaint/border-color.html b/third_party/blink/web_tests/http/tests/csspaint/border-color.html index 2520a9d..3a1a4e7 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/border-color.html +++ b/third_party/blink/web_tests/http/tests/csspaint/border-color.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../resources/run-after-layout-and-paint.js"></script> <script src="resources/test-runner-paint-worklet.js"></script> <style> @@ -159,7 +158,7 @@ </script> <script> - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/geometry-background-image-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/geometry-background-image-zoom.html index f5c1351..5bd64cf8f 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/geometry-background-image-zoom.html +++ b/third_party/blink/web_tests/http/tests/csspaint/geometry-background-image-zoom.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../resources/run-after-layout-and-paint.js"></script> <script src="./resources/test-runner-paint-worklet.js"></script> <style> html, body { margin: 0; padding: 0; } @@ -28,7 +27,7 @@ <script> document.body.style.zoom = "200%" - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/geometry-border-image-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/geometry-border-image-zoom.html index 96c1ff0..c2f1113 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/geometry-border-image-zoom.html +++ b/third_party/blink/web_tests/http/tests/csspaint/geometry-border-image-zoom.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../resources/run-after-layout-and-paint.js"></script> <script src="./resources/test-runner-paint-worklet.js"></script> <style> html, body { margin: 0; padding: 0; } @@ -34,7 +33,7 @@ <script> document.getElementById('canvas-geometry').style.borderImageOutset = '10px'; document.body.style.zoom = "200%"; - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/hidpi/geometry-with-hidpi-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/hidpi/geometry-with-hidpi-zoom.html index 7e083af..81d912d0 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/hidpi/geometry-with-hidpi-zoom.html +++ b/third_party/blink/web_tests/http/tests/csspaint/hidpi/geometry-with-hidpi-zoom.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/test-runner-paint-worklet.js"></script> <style> html, body { margin: 0; padding: 0; } @@ -35,7 +34,7 @@ <script> document.body.style.zoom = "33%"; - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/line-dash-scale-with-page-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/line-dash-scale-with-page-zoom.html index cd8d2097..6a25362 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/line-dash-scale-with-page-zoom.html +++ b/third_party/blink/web_tests/http/tests/csspaint/line-dash-scale-with-page-zoom.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../resources/run-after-layout-and-paint.js"></script> <script src="./resources/test-runner-paint-worklet.js"></script> <style> html, body { margin: 0; padding: 0; } @@ -38,7 +37,7 @@ <script> document.body.style.zoom = "200%" - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/paint2d-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/paint2d-zoom.html index d4bf63e..9015592 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/paint2d-zoom.html +++ b/third_party/blink/web_tests/http/tests/csspaint/paint2d-zoom.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../resources/run-after-layout-and-paint.js"></script> <script src="./resources/test-runner-paint-worklet.js"></script> <style> html, body { margin: 0; padding: 0; } @@ -26,7 +25,7 @@ <script> document.body.style.zoom = "300%"; - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/csspaint/resources/test-runner-paint-worklet.js b/third_party/blink/web_tests/http/tests/csspaint/resources/test-runner-paint-worklet.js index 8fd3d1b2..b8dc099c 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/resources/test-runner-paint-worklet.js +++ b/third_party/blink/web_tests/http/tests/csspaint/resources/test-runner-paint-worklet.js
@@ -1,20 +1,18 @@ -// Given a piece of 'code', runs it in the worklet, then once loaded waits for -// layout and paint, before finishing the test. +// Given a piece of 'code', runs it in the worklet, then once loaded finish the +// test (content_shell will ensure a full frame update before exit). // // Usage: -// importPaintWorkletAndTerminateTestAfterAsyncPaint('/* worklet code goes here. */'); +// importPaintWorkletThenEndTest('/* worklet code goes here. */'); -function importPaintWorkletAndTerminateTestAfterAsyncPaint(code) { +function importPaintWorkletThenEndTest(code) { if (window.testRunner) { testRunner.waitUntilDone(); } var blob = new Blob([code], {type: 'text/javascript'}); CSS.paintWorklet.addModule(URL.createObjectURL(blob)).then(function() { - runAfterLayoutAndPaint(function() { - if (window.testRunner) { - testRunner.notifyDone(); - } - }); + if (window.testRunner) { + testRunner.notifyDone(); + } }); }
diff --git a/third_party/blink/web_tests/http/tests/csspaint/shadow-scale-with-page-zoom.html b/third_party/blink/web_tests/http/tests/csspaint/shadow-scale-with-page-zoom.html index 5f08bf9..d98a875 100644 --- a/third_party/blink/web_tests/http/tests/csspaint/shadow-scale-with-page-zoom.html +++ b/third_party/blink/web_tests/http/tests/csspaint/shadow-scale-with-page-zoom.html
@@ -1,6 +1,5 @@ <!DOCTYPE html> <html> -<script src="../resources/run-after-layout-and-paint.js"></script> <script src="./resources/test-runner-paint-worklet.js"></script> <style> html, body { margin: 0; padding: 0; } @@ -37,7 +36,7 @@ <script> document.body.style.zoom = "200%" - importPaintWorkletAndTerminateTestAfterAsyncPaint(document.getElementById('code').textContent); + importPaintWorkletThenEndTest(document.getElementById('code').textContent); </script> </body> </html>
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/anonymous-image-object.js b/third_party/blink/web_tests/http/tests/devtools/tracing/anonymous-image-object.js index 2c1ab8d6..70556fa8 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/anonymous-image-object.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/anonymous-image-object.js
@@ -8,6 +8,7 @@ await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); await TestRunner.loadHTML(` + <script src="../../resources/run-after-layout-and-paint.js"></script> <style> div.marker::before { content: url(resources/test.bmp); @@ -26,7 +27,7 @@ img.addEventListener("load", onImageLoaded, false); function onImageLoaded() { - testRunner.layoutAndPaintAsyncThen(callback); + runAfterLayoutAndPaint(callback); } return promise; }
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/decode-resize.js b/third_party/blink/web_tests/http/tests/devtools/tracing/decode-resize.js index 92a5dd31..a83bd44 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/decode-resize.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/decode-resize.js
@@ -7,6 +7,7 @@ await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); await TestRunner.loadHTML(` + <script src="../../resources/run-after-layout-and-paint.js"></script> <style> div { display: inline-block; @@ -47,7 +48,7 @@ { for (let image of images) { await addImage(image); - await new Promise(fulfill => testRunner.layoutAndPaintAsyncThen(fulfill)); + await new Promise(fulfill => runAfterLayoutAndPaint(fulfill)); } return generateFrames(3);
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/scroll-invalidations.js b/third_party/blink/web_tests/http/tests/devtools/tracing/scroll-invalidations.js index 1c92ca4e..d4a5c50 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/scroll-invalidations.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/scroll-invalidations.js
@@ -7,13 +7,14 @@ await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); await TestRunner.loadHTML(` + <script src="../../resources/run-after-layout-and-paint.js"></script> <div style="width: 400px; height: 2000px; background-color: grey"></div> <div style="position: fixed; left: 50px; top: 100px; width: 50px; height: 50px; background-color: rgba(255, 100, 100, 0.6)"></div> `); await TestRunner.evaluateInPagePromise(` function scrollAndDisplay() { scrollTo(0, 200); - return new Promise(fulfill => testRunner.layoutAndPaintAsyncThen(fulfill)); + return new Promise(fulfill => runAfterLayoutAndPaint(fulfill)); } `);
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js index ad49930..ba20d38e 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-js/timeline-gc-event.js
@@ -6,11 +6,14 @@ TestRunner.addResult(`Tests the Timeline API instrumentation of a gc event\n`); await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); + await TestRunner.loadHTML(` + <script src="../../../resources/run-after-layout-and-paint.js"></script> + `); await TestRunner.evaluateInPagePromise(` function produceGarbageForGCEvents() { window.gc(); - return new Promise(fulfill => testRunner.layoutAndPaintAsyncThen(fulfill)); + return new Promise(fulfill => runAfterLayoutAndPaint(fulfill)); } `);
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-dom-gc.js b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-dom-gc.js index a3ac236..24b74ecb 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-dom-gc.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-dom-gc.js
@@ -7,11 +7,15 @@ `Tests the Timeline API instrumentation of a DOM GC event\n`); await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); + await TestRunner.loadHTML(` + <script src="../../../resources/run-after-layout-and-paint.js"></script> + `); + await TestRunner.evaluateInPagePromise(` function produceGarbageForGCEvents() { window.gc(); - return new Promise(fulfill => testRunner.layoutAndPaintAsyncThen(fulfill)); + return new Promise(fulfill => runAfterLayoutAndPaint(fulfill)); } `);
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt index 6a8db3f..1aeae29 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations-expected.txt
@@ -2,7 +2,18 @@ paint invalidations[ { - cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:21} + cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:22} + changedAttribute : undefined + changedClass : undefined + changedId : undefined + changedPseudo : undefined + extraData : "" + nodeName : "DIV class='testElement'" + selectorPart : undefined + type : "StyleRecalcInvalidationTracking" + } + { + cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:23} changedAttribute : undefined changedClass : undefined changedId : undefined @@ -24,7 +35,7 @@ type : "StyleRecalcInvalidationTracking" } { - cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:21} + cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:23} changedAttribute : undefined changedClass : undefined changedId : undefined @@ -46,7 +57,7 @@ type : "StyleRecalcInvalidationTracking" } { - cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:21} + cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:23} changedAttribute : undefined changedClass : undefined changedId : undefined @@ -68,18 +79,7 @@ type : "StyleRecalcInvalidationTracking" } { - cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:21} - changedAttribute : undefined - changedClass : undefined - changedId : undefined - changedPseudo : undefined - extraData : "" - nodeName : "DIV class='testElement'" - selectorPart : undefined - type : "StyleRecalcInvalidationTracking" - } - { - cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:22} + cause : {reason: Inline CSS style declaration was mutated, stackTrace: test://evaluations/0/timeline-grouped-invalidations.js:23} changedAttribute : undefined changedClass : undefined changedId : undefined @@ -90,6 +90,6 @@ type : "StyleRecalcInvalidationTracking" } ] -PASS - record contained Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:21 PASS - record contained Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:22 +PASS - record contained Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:23
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js index 8fa05b8..3316923d 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js
@@ -8,6 +8,7 @@ await TestRunner.showPanel('timeline'); await TestRunner.loadHTML(` <!DOCTYPE HTML> + <script src="../../../resources/run-after-layout-and-paint.js"></script> <div class="testElement">P</div><div class="testElement">A</div> <div class="testElement">S</div><div class="testElement">S</div> `); @@ -21,7 +22,7 @@ testElements[i].style.color = "red"; testElements[i].style.backgroundColor = "blue"; } - testRunner.layoutAndPaintAsyncThen(resolve); + runAfterLayoutAndPaint(resolve); }); }); } @@ -43,10 +44,10 @@ var invalidations = invalidationsTree.shadowRoot.textContent; checkStringContains( invalidations, - `Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:21`); + `Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:22`); checkStringContains( invalidations, - `Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:22`); + `Inline CSS style declaration was mutated for [ DIV class='testElement' ], [ DIV class='testElement' ], and 2 others. (anonymous) @ timeline-grouped-invalidations.js:23`); TestRunner.completeTest(); function checkStringContains(string, contains) {
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js index a8f5818..4fac56a5 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/paint-profiler-update.js
@@ -7,8 +7,9 @@ await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); await TestRunner.loadHTML(` - <div id="square" style="width: 40px; height: 40px"></div> - `); + <script src="../../../resources/run-after-layout-and-paint.js"></script> + <div id="square" style="width: 40px; height: 40px"></div> + `); await TestRunner.evaluateInPagePromise(` function performActions() { @@ -20,13 +21,13 @@ function step1() { square.style.backgroundColor = "red"; - testRunner.layoutAndPaintAsyncThen(step2); + runAfterLayoutAndPaint(step2); } function step2() { square.style.backgroundColor = "black"; - testRunner.layoutAndPaintAsyncThen(callback); + runAfterLayoutAndPaint(callback); } return promise; }
diff --git a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.js b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.js index 2abe03c..561b46c 100644 --- a/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.js +++ b/third_party/blink/web_tests/http/tests/devtools/tracing/timeline-paint/update-layer-tree.js
@@ -7,6 +7,7 @@ await TestRunner.loadModule('performance_test_runner'); await TestRunner.showPanel('timeline'); await TestRunner.loadHTML(` + <script src="../../../resources/run-after-layout-and-paint.js"></script> <style> .layer { position: absolute; @@ -23,7 +24,7 @@ var layer = document.createElement("div"); layer.classList.add("layer"); document.getElementById("parent-layer").appendChild(layer); - return new Promise((fulfill) => testRunner.layoutAndPaintAsyncThen(fulfill)); + return new Promise((fulfill) => runAfterLayoutAndPaint(fulfill)); } `);
diff --git a/third_party/blink/web_tests/http/tests/media/controls/controls-list-add-hide.html b/third_party/blink/web_tests/http/tests/media/controls/controls-list-add-hide.html index 5866f91..f77903c 100644 --- a/third_party/blink/web_tests/http/tests/media/controls/controls-list-add-hide.html +++ b/third_party/blink/web_tests/http/tests/media/controls/controls-list-add-hide.html
@@ -2,6 +2,7 @@ <title>Test adding keywords to controlsList hides buttons</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../../media-resources/media-controls.js"></script> <video controls id="enabled-controls" width="500px"></video> <script> @@ -14,12 +15,12 @@ v.controlsList.add('nodownload'); - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { assert_true(isFullscreenButtonEnabled(v)); assert_false(isDownloadsButtonEnabled(v)); v.controlsList.add('nofullscreen'); - testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => { + runAfterLayoutAndPaint(t.step_func_done(() => { assert_false(isFullscreenButtonEnabled(v)); assert_false(isDownloadsButtonEnabled(v)); }));
diff --git a/third_party/blink/web_tests/http/tests/media/controls/controls-list-remove-show.html b/third_party/blink/web_tests/http/tests/media/controls/controls-list-remove-show.html index bb58312..5b25665 100644 --- a/third_party/blink/web_tests/http/tests/media/controls/controls-list-remove-show.html +++ b/third_party/blink/web_tests/http/tests/media/controls/controls-list-remove-show.html
@@ -2,6 +2,7 @@ <title>Test removing keywords from controlsList shows buttons</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../../media-resources/media-controls.js"></script> <video controlslist="nodownload nofullscreen" id="disabled-controls" width="500px"></video> <script> @@ -14,13 +15,13 @@ v.controlsList.remove('nodownload'); - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { assert_false(isFullscreenButtonEnabled(v)); assert_true(isDownloadsButtonEnabled(v)); v.controlsList.remove('nofullscreen'); - testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => { + runAfterLayoutAndPaint(t.step_func_done(() => { assert_true(isFullscreenButtonEnabled(v)); assert_true(isDownloadsButtonEnabled(v)); }));
diff --git a/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js b/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js index e317341..bf2ed0c 100644 --- a/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js +++ b/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js
@@ -1,26 +1,34 @@ -// Run a callback after layout and paint of all pending document changes. +// Run a callback after a frame update. // -// It has two modes: -// - traditional mode, for existing tests, and tests needing customized notifyDone timing: -// Usage: +// Note that this file has two copies: +// resources/run-after-layout-and-paint.js +// and +// http/tests/resources/run-after-layout-and-paint.js. +// They should be kept always the same. +// +// The function runAfterLayoutAndPaint() has two modes: +// - traditional mode, for existing tests, and tests needing customized +// notifyDone timing: // if (window.testRunner) // testRunner.waitUntilDone(); // runAfterLayoutAndPaint(function() { // ... // some code which modifies style/layout // if (window.testRunner) // testRunner.notifyDone(); -// // Or to ensure the next paint is executed before the test finishes: -// // if (window.testRunner) -// // runAfterAfterLayoutAndPaint(function() { testRunner.notifyDone() }); // // Or notifyDone any time later if needed. // }); // -// - autoNotifyDone mode, for new tests which just need to change style/layout and finish: -// Usage: +// - autoNotifyDone mode, for new tests which just need to change style/layout +// and finish: // runAfterLayoutAndPaint(function() { // ... // some code which modifies style/layout // }, true); - +// +// Note that because we always update a frame before finishing a test, +// we don't need +// runAfterLayoutAndPaint(function() { testRunner.notifyDone(); }) +// to ensure the test finish after a frame update. +// if (window.internals) internals.runtimeFlags.paintUnderInvalidationCheckingEnabled = true; @@ -35,9 +43,18 @@ if (autoNotifyDone) testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function() { - callback(); - if (autoNotifyDone) - testRunner.notifyDone(); + // We do requestAnimationFrame and setTimeout to ensure a frame has started + // and layout and paint have run. The requestAnimationFrame fires after the + // frame has started but before layout and paint. The setTimeout fires + // at the beginning of the next frame, meaning that the previous frame has + // completed layout and paint. + // See http://crrev.com/c/1395193/10/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js + // for more discussions. + requestAnimationFrame(function() { + setTimeout(function() { + callback(); + if (autoNotifyDone) + testRunner.notifyDone(); + }, 0); }); }
diff --git a/third_party/blink/web_tests/images/animated-gif-fast-crash.html b/third_party/blink/web_tests/images/animated-gif-fast-crash.html index 2214ad9..379aa1f 100644 --- a/third_party/blink/web_tests/images/animated-gif-fast-crash.html +++ b/third_party/blink/web_tests/images/animated-gif-fast-crash.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> Tests fast animating gif (10ms per frame). Passes if it doesn't crash.<br> <img src="resources/animated-10color-fast.gif"> +<script src="../resources/run-after-layout-and-paint.js"></script> <script> // Busy-wait 50ms to trigger the bug of invalidation during paint. @@ -16,7 +17,7 @@ function displayOneFrame() { delay(); if (--count >= 0) - testRunner.layoutAndPaintAsyncThen(displayOneFrame); + runAfterLayoutAndPaint(displayOneFrame); else testRunner.notifyDone(); }
diff --git a/third_party/blink/web_tests/images/animated-gif-with-offsets.html b/third_party/blink/web_tests/images/animated-gif-with-offsets.html index 26db055..3d118de 100644 --- a/third_party/blink/web_tests/images/animated-gif-with-offsets.html +++ b/third_party/blink/web_tests/images/animated-gif-with-offsets.html
@@ -4,6 +4,7 @@ doesn't crash, we're good. <img src="resources/animated-gif-with-offsets.gif"> </body> +<script src="../resources/run-after-layout-and-paint.js"></script> <script> // Delay 50ms for each frame. @@ -17,7 +18,7 @@ function displayOneFrame() { delay(); if (--count >= 0) - testRunner.layoutAndPaintAsyncThen(displayOneFrame); + runAfterLayoutAndPaint(displayOneFrame); else testRunner.notifyDone(); }
diff --git a/third_party/blink/web_tests/images/resources/color-checker-munsell-chart.js b/third_party/blink/web_tests/images/resources/color-checker-munsell-chart.js index 4b213b4..951389b 100644 --- a/third_party/blink/web_tests/images/resources/color-checker-munsell-chart.js +++ b/third_party/blink/web_tests/images/resources/color-checker-munsell-chart.js
@@ -6,7 +6,7 @@ var image = document.querySelector('img'); image.onload = function() { - runAfterLayoutAndPaint(function () { setTimeout(drawImageToCanvas, 0) }); + runAfterLayoutAndPaint(drawImageToCanvas); }; image.src = source;
diff --git a/third_party/blink/web_tests/inspector-protocol/animation/animation-pause-infinite.js b/third_party/blink/web_tests/inspector-protocol/animation/animation-pause-infinite.js index 837fa28..e928d32 100644 --- a/third_party/blink/web_tests/inspector-protocol/animation/animation-pause-infinite.js +++ b/third_party/blink/web_tests/inspector-protocol/animation/animation-pause-infinite.js
@@ -1,5 +1,6 @@ (async function(testRunner) { var {page, session, dp} = await testRunner.startHTML(` + <script src='../../resources/run-after-layout-and-paint.js'></script> <div id='node' style='background-color: red; height: 100px'></div> `, 'Tests that the animation is correctly paused.'); @@ -17,8 +18,7 @@ (function rafWidth() { var callback; var promise = new Promise((fulfill) => callback = fulfill); - if (window.testRunner) - testRunner.layoutAndPaintAsyncThen(() => callback(node.offsetWidth)); + runAfterLayoutAndPaint(() => callback(node.offsetWidth)); return promise; })() `);
diff --git a/third_party/blink/web_tests/inspector-protocol/animation/animation-pause.js b/third_party/blink/web_tests/inspector-protocol/animation/animation-pause.js index 37cfa58..238c974a 100644 --- a/third_party/blink/web_tests/inspector-protocol/animation/animation-pause.js +++ b/third_party/blink/web_tests/inspector-protocol/animation/animation-pause.js
@@ -1,5 +1,6 @@ (async function(testRunner) { var {page, session, dp} = await testRunner.startHTML(` + <script src='../../resources/run-after-layout-and-paint.js'></script> <div id='node' style='background-color: red; height: 100px'></div> `, 'Tests that the animation is correctly paused.'); @@ -17,8 +18,7 @@ (function rafWidth() { var callback; var promise = new Promise((fulfill) => callback = fulfill); - if (window.testRunner) - testRunner.layoutAndPaintAsyncThen(() => callback(node.offsetWidth)); + runAfterLayoutAndPaint(() => callback(node.offsetWidth)); return promise; })() `);
diff --git a/third_party/blink/web_tests/inspector-protocol/animation/animation-seek-past-end.js b/third_party/blink/web_tests/inspector-protocol/animation/animation-seek-past-end.js index 37dc66c..34206650 100644 --- a/third_party/blink/web_tests/inspector-protocol/animation/animation-seek-past-end.js +++ b/third_party/blink/web_tests/inspector-protocol/animation/animation-seek-past-end.js
@@ -1,5 +1,6 @@ (async function(testRunner) { var {page, session, dp} = await testRunner.startHTML(` + <script src='../../resources/run-after-layout-and-paint.js'></script> <div id='node' style='background-color: red; height: 100px; width: 100px'></div> `, 'Tests seeking animation past end time.'); @@ -16,8 +17,7 @@ (function rafWidth() { var callback; var promise = new Promise((fulfill) => callback = fulfill); - if (window.testRunner) - testRunner.layoutAndPaintAsyncThen(() => callback(node.offsetWidth)); + runAfterLayoutAndPaint(() => callback(node.offsetWidth)); return promise; })() `);
diff --git a/third_party/blink/web_tests/media/controls-slider-appearance-crash.html b/third_party/blink/web_tests/media/controls-slider-appearance-crash.html index e398a65..ff43cf30 100644 --- a/third_party/blink/web_tests/media/controls-slider-appearance-crash.html +++ b/third_party/blink/web_tests/media/controls-slider-appearance-crash.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <script src="../resources/js-test.js"></script> +<script src="../resources/run-after-layout-and-paint.js"></script> <script> description("This test ensures that applying media control slider thumb appearance to pseudo-elements does not cause a crash."); </script> @@ -25,6 +26,6 @@ <script> if (window.testRunner) { testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function() { testRunner.notifyDone(); }); + runAfterLayoutAndPaint(function() { testRunner.notifyDone(); }); } </script>
diff --git a/third_party/blink/web_tests/media/controls/buttons-after-reset.html b/third_party/blink/web_tests/media/controls/buttons-after-reset.html index 9bca350..496e966 100644 --- a/third_party/blink/web_tests/media/controls/buttons-after-reset.html +++ b/third_party/blink/web_tests/media/controls/buttons-after-reset.html
@@ -2,6 +2,7 @@ <html> <title>Test that resetting the controls after load is a no-op.</title> <script src="../media-controls.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <video controls width=400> <track kind=subtitles src=fake-en-sub.vtt srclang=en label=English> <track kind=subtitles src=fake-fr-sub.vtt srclang=fr label=French> @@ -15,10 +16,10 @@ video.src = '../content/test.ogv'; video.addEventListener('loadedmetadata', () => { video.controls = false; - testRunner.layoutAndPaintAsyncThen(() => { + runAfterLayoutAndPaint(() => { video.controls = true; - testRunner.layoutAndPaintAsyncThen(() => { + runAfterLayoutAndPaint(() => { testRunner.notifyDone(); }); });
diff --git a/third_party/blink/web_tests/media/controls/captions-menu-always-visible-expected.html b/third_party/blink/web_tests/media/controls/captions-menu-always-visible-expected.html index ce92e5c..b3473a9 100644 --- a/third_party/blink/web_tests/media/controls/captions-menu-always-visible-expected.html +++ b/third_party/blink/web_tests/media/controls/captions-menu-always-visible-expected.html
@@ -28,8 +28,7 @@ // :hover sometimes applying. textTrackMenu(video).style = 'pointer-events: none;'; - testRunner.layoutAndPaintAsyncThen(() => { + if (window.testRunner) testRunner.notifyDone(); - }); }); </script>
diff --git a/third_party/blink/web_tests/media/controls/captions-menu-always-visible.html b/third_party/blink/web_tests/media/controls/captions-menu-always-visible.html index c361949..7507a2c5 100644 --- a/third_party/blink/web_tests/media/controls/captions-menu-always-visible.html +++ b/third_party/blink/web_tests/media/controls/captions-menu-always-visible.html
@@ -1,6 +1,7 @@ <!DOCTYPE html> <title>Captions menu always visible</title> <script src="../media-controls.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <style> .container { overflow: hidden; @@ -31,7 +32,7 @@ // :hover sometimes applying. textTrackMenu(video).style = 'pointer-events: none;'; - testRunner.layoutAndPaintAsyncThen(() => { + runAfterLayoutAndPaint(() => { testRunner.notifyDone(); }); });
diff --git a/third_party/blink/web_tests/media/controls/controls-layout-in-different-size.html b/third_party/blink/web_tests/media/controls/controls-layout-in-different-size.html index 143b16a..7d0b0898 100644 --- a/third_party/blink/web_tests/media/controls/controls-layout-in-different-size.html +++ b/third_party/blink/web_tests/media/controls/controls-layout-in-different-size.html
@@ -3,6 +3,7 @@ <title>Media Controls: Test controls layout correctly in different small sizes.</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <video controls></video> <script> @@ -23,7 +24,7 @@ function runTestCase(index) { let test = testCases[index]; video.width = test; - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { expectLayoutCorrectly(); assert_not_equals(getComputedStyle(overflowBtn), 'none',
diff --git a/third_party/blink/web_tests/media/controls/download-button-displays-with-preload-none.html b/third_party/blink/web_tests/media/controls/download-button-displays-with-preload-none.html index e1e6c46..c4fd9d4 100644 --- a/third_party/blink/web_tests/media/controls/download-button-displays-with-preload-none.html +++ b/third_party/blink/web_tests/media/controls/download-button-displays-with-preload-none.html
@@ -2,13 +2,14 @@ <title>media controls download button preload none</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <video controls preload="none" src="https://someexample.example/example.mp4"></video> <script> async_test(function(t) { var video = document.querySelector("video"); - testRunner.layoutAndPaintAsyncThen(t.step_func_done(function() { + runAfterLayoutAndPaint(t.step_func_done(function() { assert_true(isDownloadsButtonEnabled(video)); }));
diff --git a/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html b/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html index ced98b1..c272e2a 100644 --- a/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html +++ b/third_party/blink/web_tests/media/controls/large-overflow-menu-when-pip-enabled.html
@@ -2,6 +2,7 @@ <title>Large overflow menu when pip enabled</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <body> <video controls></video> @@ -20,11 +21,11 @@ expectOverflowMenuAndTrackListContainsPip(); video.setAttribute('disablepictureinpicture', ''); - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { expectOverflowMenuAndTrackListNotContainsPip(); video.removeAttribute('disablepictureinpicture'); - testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => { + runAfterLayoutAndPaint(t.step_func_done(() => { expectOverflowMenuAndTrackListContainsPip(); })); }));
diff --git a/third_party/blink/web_tests/media/controls/modern/immersive-mode-adds-css-class.html b/third_party/blink/web_tests/media/controls/modern/immersive-mode-adds-css-class.html index 61a49242..9dd1f748 100644 --- a/third_party/blink/web_tests/media/controls/modern/immersive-mode-adds-css-class.html +++ b/third_party/blink/web_tests/media/controls/modern/immersive-mode-adds-css-class.html
@@ -3,6 +3,7 @@ <title>Test that enabling immersive mode adds the immersive mode CSS class.</title> <script src="../../../resources/testharness.js"></script> <script src="../../../resources/testharnessreport.js"></script> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../../media-controls.js"></script> <video controls width=400 preload=metadata src="../../content/60_sec_video.webm"></video> <script> @@ -19,7 +20,7 @@ // Make sure that we still respect immersive mode when enlarged. video.width = 1000; - testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => { + runAfterLayoutAndPaint(t.step_func_done(() => { assert_true(controls.classList.contains(immersiveModeCSSClass)); checkThatVRCSSRulesAreRespected(); }));
diff --git a/third_party/blink/web_tests/media/controls/overflow-menu-always-visible-expected.html b/third_party/blink/web_tests/media/controls/overflow-menu-always-visible-expected.html index 4a69e0f..327ea430 100644 --- a/third_party/blink/web_tests/media/controls/overflow-menu-always-visible-expected.html +++ b/third_party/blink/web_tests/media/controls/overflow-menu-always-visible-expected.html
@@ -10,9 +10,6 @@ </style> <video controls muted></video> <script> - if (window.testRunner) - testRunner.waitUntilDone(); - var video = document.querySelector('video'); enableTestMode(video); video.src = '../content/test.ogv'; @@ -26,9 +23,5 @@ // Disabling pointer events on the overflow menu to avoid a flakyness with // :hover sometimes applying. overflowMenu(video).style = 'pointer-events: none;'; - - testRunner.layoutAndPaintAsyncThen(() => { - testRunner.notifyDone(); - }); }); </script>
diff --git a/third_party/blink/web_tests/media/controls/overflow-menu-always-visible.html b/third_party/blink/web_tests/media/controls/overflow-menu-always-visible.html index ffcc86f..602edd8 100644 --- a/third_party/blink/web_tests/media/controls/overflow-menu-always-visible.html +++ b/third_party/blink/web_tests/media/controls/overflow-menu-always-visible.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <title>Overflow menu always visible</title> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <style> .container { @@ -30,7 +31,7 @@ // :hover sometimes applying. overflowMenu(video).style = 'pointer-events: none;'; - testRunner.layoutAndPaintAsyncThen(() => { + runAfterLayoutAndPaint(() => { testRunner.notifyDone(); }); });
diff --git a/third_party/blink/web_tests/media/controls/overflow-menu-animation.html b/third_party/blink/web_tests/media/controls/overflow-menu-animation.html index 69cc4a2..3d5c070 100644 --- a/third_party/blink/web_tests/media/controls/overflow-menu-animation.html +++ b/third_party/blink/web_tests/media/controls/overflow-menu-animation.html
@@ -2,6 +2,7 @@ <title>Media Controls: overflow menu item list animation.</title> <script src='../../resources/testharness.js'></script> <script src='../../resources/testharnessreport.js'></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src='../media-controls.js'></script> <video controls width=400></video> <script> @@ -18,7 +19,7 @@ function runTestCase(index) { video.width = testCasesWidth[index]; - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { // Go through item list, check 'animated-##' class is presented if item is displayed // and check if the items' classes are in sequential order
diff --git a/third_party/blink/web_tests/media/controls/overlay-play-button-document-move.html b/third_party/blink/web_tests/media/controls/overlay-play-button-document-move.html index cacba37..f39d8fc 100644 --- a/third_party/blink/web_tests/media/controls/overlay-play-button-document-move.html +++ b/third_party/blink/web_tests/media/controls/overlay-play-button-document-move.html
@@ -2,6 +2,7 @@ <title>media controls overlay play button document move</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <script src="overlay-play-button.js"></script> <body> @@ -19,22 +20,22 @@ // If the width goes under the minimum, the button should be hidden. video.width = NARROW_VIDEO_WIDTH; - testRunner.layoutAndPaintAsyncThen(t.step_func(function() { + runAfterLayoutAndPaint(t.step_func(function() { assertOverlayPlayButtonNotVisible(video); // Re-widening the video should display the button. video.width = NORMAL_VIDEO_WIDTH; - testRunner.layoutAndPaintAsyncThen(t.step_func(function() { + runAfterLayoutAndPaint(t.step_func(function() { assertOverlayPlayButtonVisible(video); // If the height goes under the minimum, the button should be hidden. video.height = NARROW_VIDEO_HEIGHT; - testRunner.layoutAndPaintAsyncThen(t.step_func(function() { + runAfterLayoutAndPaint(t.step_func(function() { assertOverlayPlayButtonNotVisible(video); // Re-heightening the video should display the button. video.height = NORMAL_VIDEO_HEIGHT; - testRunner.layoutAndPaintAsyncThen(t.step_func_done(function() { + runAfterLayoutAndPaint(t.step_func_done(function() { assertOverlayPlayButtonVisible(video); })); }));
diff --git a/third_party/blink/web_tests/media/controls/overlay-play-button-narrow.html b/third_party/blink/web_tests/media/controls/overlay-play-button-narrow.html index 248a6a4..66d4b80 100644 --- a/third_party/blink/web_tests/media/controls/overlay-play-button-narrow.html +++ b/third_party/blink/web_tests/media/controls/overlay-play-button-narrow.html
@@ -2,6 +2,7 @@ <title>media controls overlay play button narrow</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <script src="overlay-play-button.js"></script> <body> @@ -24,22 +25,22 @@ // If the width goes under the minimum, the button should be hidden. video.width = NARROW_VIDEO_WIDTH; - testRunner.layoutAndPaintAsyncThen(t.step_func(function() { + runAfterLayoutAndPaint(t.step_func(function() { assertOverlayPlayButtonNotVisible(video); // Re-widening the video should display the button. video.width = NORMAL_VIDEO_WIDTH; - testRunner.layoutAndPaintAsyncThen(t.step_func(function() { + runAfterLayoutAndPaint(t.step_func(function() { assertOverlayPlayButtonVisible(video); // If the height goes under the minimum, the button should be hidden. video.height = NARROW_VIDEO_HEIGHT; - testRunner.layoutAndPaintAsyncThen(t.step_func(function() { + runAfterLayoutAndPaint(t.step_func(function() { assertOverlayPlayButtonNotVisible(video); // Re-heightening the video should display the button. video.height = NORMAL_VIDEO_HEIGHT; - testRunner.layoutAndPaintAsyncThen(t.step_func_done(function() { + runAfterLayoutAndPaint(t.step_func_done(function() { assertOverlayPlayButtonVisible(video); })); }));
diff --git a/third_party/blink/web_tests/media/controls/resizing-changes-css-class.html b/third_party/blink/web_tests/media/controls/resizing-changes-css-class.html index 741625d..0d1592f0 100644 --- a/third_party/blink/web_tests/media/controls/resizing-changes-css-class.html +++ b/third_party/blink/web_tests/media/controls/resizing-changes-css-class.html
@@ -3,6 +3,7 @@ <title>Test that sizing changes are reflected in CSS classes.</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <video controls width=200 preload=none></video> <script> @@ -26,7 +27,7 @@ function runTestCase(index) { let test = testCases[index]; video.width = test.width; - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { test.expect(); let nextIndex = index + 1; if (nextIndex === testCases.length) {
diff --git a/third_party/blink/web_tests/media/controls/settings-disable-controls.html b/third_party/blink/web_tests/media/controls/settings-disable-controls.html index d753eb1..63735381 100644 --- a/third_party/blink/web_tests/media/controls/settings-disable-controls.html +++ b/third_party/blink/web_tests/media/controls/settings-disable-controls.html
@@ -2,6 +2,7 @@ <title>Test that 'mediaControlsEnabled' properly toggles the native controls</title> <script src="../../resources/testharness.js"></script> <script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script src="../media-controls.js"></script> <video controls></video> <script> @@ -23,12 +24,12 @@ assert_not_equals(mediaControlsButton(video, "panel").style.display, "none"); internals.settings.setMediaControlsEnabled(false); - testRunner.layoutAndPaintAsyncThen(t.step_func(() => { + runAfterLayoutAndPaint(t.step_func(() => { assert_equals(mediaControlsButton(video, "panel").style.display, "none"); assert_equals(overlayCastButton(video).style.display, "none"); internals.settings.setMediaControlsEnabled(true); - testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => { + runAfterLayoutAndPaint(t.step_func_done(() => { assert_not_equals(mediaControlsButton(video, "panel").style.display, "none"); assert_equals(overlayCastButton(video).style.display, "none"); }));
diff --git a/third_party/blink/web_tests/media/resources/munsell-video-chart.js b/third_party/blink/web_tests/media/resources/munsell-video-chart.js index 8efbe02..2f7fce82 100644 --- a/third_party/blink/web_tests/media/resources/munsell-video-chart.js +++ b/third_party/blink/web_tests/media/resources/munsell-video-chart.js
@@ -5,7 +5,7 @@ var image = document.querySelector('img'); image.onload = function() { - runAfterLayoutAndPaint(function () { setTimeout(drawImageToCanvas, 0) }); + runAfterLayoutAndPaint(drawImageToCanvas); }; image.src = source;
diff --git a/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html b/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html index 8982077..47e3be2c 100644 --- a/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html +++ b/third_party/blink/web_tests/media/video-controls-overflow-menu-fullscreen-button.html
@@ -2,6 +2,7 @@ <title>Clicking on the overflow fullscreen button opens the video in fullscreen.</title> <script src="../resources/testharness.js"></script> <script src="../resources/testharnessreport.js"></script> +<script src="../resources/run-after-layout-and-paint.js"></script> <script src="media-controls.js"></script> <script src="overflow-menu.js"></script> @@ -33,7 +34,7 @@ document.onwebkitfullscreenchange = t.step_func(() => { assert_equals(document.fullscreenElement, video); // Hiding the overflow menu is triggered by layout. - testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => { + runAfterLayoutAndPaint(t.step_func_done(() => { assert_equals(getComputedStyle(overflowMenu).display, "none"); })); });
diff --git a/third_party/blink/web_tests/media/video-persistence-expected.html b/third_party/blink/web_tests/media/video-persistence-expected.html index 6d52a37..bdb3365f 100644 --- a/third_party/blink/web_tests/media/video-persistence-expected.html +++ b/third_party/blink/web_tests/media/video-persistence-expected.html
@@ -55,9 +55,7 @@ }); document.addEventListener('webkitfullscreenchange', e => { - testRunner.layoutAndPaintAsyncThen(() => { - testRunner.notifyDone(); - }); + testRunner.notifyDone(); }); } </script>
diff --git a/third_party/blink/web_tests/media/video-persistence.html b/third_party/blink/web_tests/media/video-persistence.html index a9112eb..4f31080 100644 --- a/third_party/blink/web_tests/media/video-persistence.html +++ b/third_party/blink/web_tests/media/video-persistence.html
@@ -50,10 +50,7 @@ document.addEventListener('webkitfullscreenchange', e => { internals.setPersistent(video, true); - - testRunner.layoutAndPaintAsyncThen(() => { - testRunner.notifyDone(); - }); + testRunner.notifyDone(); }); } </script>
diff --git a/third_party/blink/web_tests/paint/background/scrolling-background-with-negative-z-child.html b/third_party/blink/web_tests/paint/background/scrolling-background-with-negative-z-child.html index 89b02050..0f4634f 100644 --- a/third_party/blink/web_tests/paint/background/scrolling-background-with-negative-z-child.html +++ b/third_party/blink/web_tests/paint/background/scrolling-background-with-negative-z-child.html
@@ -1,4 +1,5 @@ <!doctype html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <style> #container { overflow: scroll; @@ -22,16 +23,7 @@ <div id="compositedChild"></div> </div> <script> - if (window.testRunner) { - testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function() { - document.getElementById('container').scrollTop = 1000; - testRunner.notifyDone(); - }); - } else { - // For manual testing. - setTimeout(function() { - document.getElementById('container').scrollTop = 1000; - }, 500); - } + runAfterLayoutAndPaint(function() { + document.getElementById('container').scrollTop = 1000; + }, true); </script>
diff --git a/third_party/blink/web_tests/paint/invalidation/background/obscured-background-no-repaint.html b/third_party/blink/web_tests/paint/invalidation/background/obscured-background-no-repaint.html index 2b7e28c..399fd65 100644 --- a/third_party/blink/web_tests/paint/invalidation/background/obscured-background-no-repaint.html +++ b/third_party/blink/web_tests/paint/invalidation/background/obscured-background-no-repaint.html
@@ -1,5 +1,6 @@ <html> <head> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <style type="text/css"> #test1 div { height: 100px; @@ -74,12 +75,12 @@ // Ensure the deferred decoder has decoded ../resources/apple.jpg. testRunner.updateAllLifecyclePhasesAndCompositeThen(function() { internals.advanceImageAnimation(imgForAdvanceImageAnimation); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { internals.startTrackingRepaints(document); internals.advanceImageAnimation(imgForAdvanceImageAnimation); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { internals.advanceImageAnimation(imgForAdvanceImageAnimation); - testRunner.layoutAndPaintAsyncThen(finish); + runAfterLayoutAndPaint(finish); }); }); });
diff --git a/third_party/blink/web_tests/paint/invalidation/resources/text-based-repaint.js b/third_party/blink/web_tests/paint/invalidation/resources/text-based-repaint.js index a9966490..f55bd95 100644 --- a/third_party/blink/web_tests/paint/invalidation/resources/text-based-repaint.js +++ b/third_party/blink/web_tests/paint/invalidation/resources/text-based-repaint.js
@@ -28,11 +28,16 @@ else testRunner.dumpAsText(); - testRunner.layoutAndPaintAsyncThen(function() { - internals.startTrackingRepaints(top.document); - repaintTest(); - if (!window.testIsAsync) - finishRepaintTest(); + // This is equivalent to runAfterLayoutAndPaint() in + // ../../resources/run-after-layout-and-paint.js. Duplicate it here so that + // the callers don't need to include that file. + requestAnimationFrame(() => { + setTimeout(() => { + internals.startTrackingRepaints(top.document); + repaintTest(); + if (!window.testIsAsync) + finishRepaintTest(); + }, 0); }); } @@ -42,22 +47,11 @@ runRepaintTest(); } -function forceStyleRecalc() -{ - if (document.body) - document.body.clientTop; - else if (document.documentElement) - document.documentElement.clientTop; -} - function finishRepaintTest() { if (!window.testRunner || !window.internals) return; - // Force a style recalc. - forceStyleRecalc(); - var flags = internals.LAYER_TREE_INCLUDES_PAINT_INVALIDATIONS; if (window.layerTreeAsTextAdditionalFlags)
diff --git a/third_party/blink/web_tests/paint/invalidation/resources/window-resize-repaint.js b/third_party/blink/web_tests/paint/invalidation/resources/window-resize-repaint.js index ae0d641a..c5ef19e 100644 --- a/third_party/blink/web_tests/paint/invalidation/resources/window-resize-repaint.js +++ b/third_party/blink/web_tests/paint/invalidation/resources/window-resize-repaint.js
@@ -21,7 +21,7 @@ if (sizeIndex < testSizes.length) { internals.startTrackingRepaints(document); window.resizeTo(testSizes[sizeIndex].width, testSizes[sizeIndex].height); - testRunner.layoutAndPaintAsyncThen(doTest); + runAfterLayoutAndPaint(doTest); } else if (window.testRunner) { testRunner.setCustomTextOutput(repaintRects); testRunner.notifyDone(); @@ -33,6 +33,6 @@ testRunner.waitUntilDone(); onload = function() { window.resizeTo(testSizes[0].width, testSizes[0].height); - testRunner.layoutAndPaintAsyncThen(doTest); + runAfterLayoutAndPaint(doTest); }; }
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container.html b/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container.html index 4a0d229..c9c73d8 100644 --- a/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container.html +++ b/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <script src="../../../editing/editing.js"></script> <input id="root" style="will-change: transform" size="5" value="test test test"> @@ -11,7 +12,7 @@ function repaintTest() { root.focus(); root.scrollLeft = 200; - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { execMoveSelectionForwardByWordCommand(); execMoveSelectionForwardByWordCommand(); execMoveSelectionForwardByWordCommand();
diff --git a/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container.html b/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container.html index dcd95ff..4210de6 100644 --- a/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container.html +++ b/third_party/blink/web_tests/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <script src="../../../editing/editing.js"></script> <input id="root" style="will-change: transform" size="5" value="test test test"> @@ -11,7 +12,7 @@ function repaintTest() { root.focus(); root.scrollLeft = 200; - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { execMoveSelectionForwardByWordCommand(); execMoveSelectionForwardByWordCommand(); execMoveSelectionForwardByWordCommand();
diff --git a/third_party/blink/web_tests/paint/invalidation/selection/selection-in-composited-scrolling-container.html b/third_party/blink/web_tests/paint/invalidation/selection/selection-in-composited-scrolling-container.html index 0e886f7..35ca562 100644 --- a/third_party/blink/web_tests/paint/invalidation/selection/selection-in-composited-scrolling-container.html +++ b/third_party/blink/web_tests/paint/invalidation/selection/selection-in-composited-scrolling-container.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <input id="target" size="5" value="test test test"> <script> @@ -10,7 +11,7 @@ function repaintTest() { target.focus(); target.scrollLeft = 200; - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { target.setSelectionRange(5, 10); finishRepaintTest(); });
diff --git a/third_party/blink/web_tests/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html b/third_party/blink/web_tests/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html index 9f4151bd..69ca757 100644 --- a/third_party/blink/web_tests/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html +++ b/third_party/blink/web_tests/paint/invalidation/selection/selection-in-non-composited-scrolling-container.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <input id="target"size="5" value="test test test"> <script> @@ -10,7 +11,7 @@ function repaintTest() { target.focus(); target.scrollLeft = 5; - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { target.setSelectionRange(5, 10); finishRepaintTest(); });
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/feImage-target-reappend-to-document.svg b/third_party/blink/web_tests/paint/invalidation/svg/feImage-target-reappend-to-document.svg index a6a2bc8..ca2ac50 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/feImage-target-reappend-to-document.svg +++ b/third_party/blink/web_tests/paint/invalidation/svg/feImage-target-reappend-to-document.svg
@@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> + <script xlink:href="../../../resources/run-after-layout-and-paint.js"></script> <script xlink:href="../resources/text-based-repaint.js"></script> <title>There should be a single green 100x100 square.</title> <defs> @@ -20,7 +21,7 @@ var greenImage = document.getElementById("feimage-green"); document.getElementById("filter").removeChild(greenImage); - testRunner.layoutAndPaintAsyncThen(function() { + runAfterLayoutAndPaint(function() { document.getElementById("filter").appendChild(greenImage); finishRepaintTest(); });
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/js-late-mask-and-object-creation.svg b/third_party/blink/web_tests/paint/invalidation/svg/js-late-mask-and-object-creation.svg index bd34aaca..e5861f1e 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/js-late-mask-and-object-creation.svg +++ b/third_party/blink/web_tests/paint/invalidation/svg/js-late-mask-and-object-creation.svg
@@ -1,6 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="svg-root" width="100%" height="100%" viewBox="0 0 800 600" onload="runRepaintAndPixelTest()"> +<script xlink:href="../../../resources/run-after-layout-and-paint.js"/> <script xlink:href="../resources/text-based-repaint.js"/> <g id="content"/> @@ -10,7 +11,7 @@ var content = document.getElementById("content"); function repaintTest() { - testRunner.layoutAndPaintAsyncThen(createObject); + createObject(); } function createObject() @@ -23,7 +24,7 @@ rect.setAttribute("mask", "url(#dynMask)"); content.appendChild(rect); - testRunner.layoutAndPaintAsyncThen(createMask); + runAfterLayoutAndPaint(createMask); } function createMask()
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation-expected.txt b/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation-expected.txt index 30a8bab7..257c371 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation-expected.txt
@@ -29,6 +29,26 @@ }, { "object": "LayoutSVGRect rect", + "rect": [200, 100, 403, 249], + "reason": "chunk appeared" + }, + { + "object": "LayoutSVGRect rect", + "rect": [200, 100, 403, 249], + "reason": "chunk appeared" + }, + { + "object": "LayoutSVGRect rect", + "rect": [200, 100, 403, 249], + "reason": "chunk disappeared" + }, + { + "object": "LayoutSVGRect rect", + "rect": [200, 100, 403, 249], + "reason": "chunk disappeared" + }, + { + "object": "LayoutSVGRect rect", "rect": [100, 100, 403, 249], "reason": "chunk appeared" },
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation.svg b/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation.svg index 47b1034..df86666 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation.svg +++ b/third_party/blink/web_tests/paint/invalidation/svg/mask-invalidation.svg
@@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" onload="runRepaintAndPixelTest()"> +<script xlink:href="../../../resources/run-after-layout-and-paint.js"></script> <script xlink:href="../resources/text-based-repaint.js"/> <script> window.testIsAsync = true; @@ -24,7 +25,7 @@ function repaintTest() { draw(150, 50); - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { draw(50, 50); finishRepaintTest(); });
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem-expected.txt b/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem-expected.txt index 2ccb818..4f41439 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem-expected.txt
@@ -20,10 +20,20 @@ { "object": "LayoutSVGRect rect id='move'", "rect": [28, 38, 10, 10], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRect rect id='move'", + "rect": [28, 18, 10, 10], "reason": "chunk appeared" }, { "object": "LayoutSVGRect rect id='move'", + "rect": [28, 18, 10, 10], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRect rect id='move'", "rect": [18, 18, 10, 10], "reason": "disappeared" }
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem.html b/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem.html index b0c3d165..895e5b7 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem.html +++ b/third_party/blink/web_tests/paint/invalidation/svg/modify-inserted-listitem.html
@@ -3,6 +3,7 @@ <rect id="ref" x="20" y="30" width="10" height="10" fill="red"></rect> <rect id="move" x="10" y="10" width="10" height="10" fill="green"></rect> </svg> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <script> testIsAsync = true; @@ -13,10 +14,9 @@ transform.matrix.e = 10; document.querySelector('#move').transform.baseVal.appendItem(transform); - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { transform.matrix.f = 20; - if (window.testRunner) - finishRepaintTest(); + finishRepaintTest(); }); } </script>
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-different-attr.html b/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-different-attr.html index 86737dbc..02a6c215 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-different-attr.html +++ b/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-different-attr.html
@@ -13,6 +13,7 @@ <text id="target" x="15" y="10 20" fill="green">A B C</text> <text id="source" x="50" y="50 60" fill="blue">X Y Z</text> </svg> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <script> testIsAsync = true; @@ -22,10 +23,9 @@ var moved = document.querySelector('#source').y.baseVal.removeItem(1); document.querySelector('#target').x.baseVal.appendItem(moved); - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { moved.value = 65; - if (window.testRunner) - finishRepaintTest(); + finishRepaintTest(); }); } </script>
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-expected.txt b/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-expected.txt index 04c85d1f..cda0c1a3 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem-expected.txt
@@ -21,6 +21,11 @@ "object": "LayoutSVGPath polygon id='target'", "rect": [18, 18, 30, 20], "reason": "full" + }, + { + "object": "LayoutSVGPath polygon id='target'", + "rect": [18, 18, 20, 20], + "reason": "full" } ] }
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem.html b/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem.html index 52ab1488..7b4f493 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem.html +++ b/third_party/blink/web_tests/paint/invalidation/svg/modify-transferred-listitem.html
@@ -4,6 +4,7 @@ <polygon id="target" points="20,10 10,30 30,30" fill="green"></polygon> <polygon id="source" points="20,20" fill="blue"></polygon> </svg> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <script> testIsAsync = true; @@ -13,11 +14,10 @@ var moved = document.querySelector('#source').points.removeItem(0); document.querySelector('#target').points.appendItem(moved); - requestAnimationFrame(function() { + runAfterLayoutAndPaint(function() { moved.x = 40; moved.y = 10; - if (window.testRunner) - finishRepaintTest(); + finishRepaintTest(); }); } </script>
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt b/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt index 6ba0ad1..b12e613 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt +++ b/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div-expected.txt
@@ -104,6 +104,16 @@ }, { "object": "LayoutBlockFlow (positioned) div id='html' class='outerBox'", + "rect": [415, 125, 150, 150], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow (positioned) div id='html' class='outerBox'", + "rect": [415, 125, 150, 150], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow (positioned) div id='html' class='outerBox'", "rect": [400, 100, 150, 150], "reason": "geometry" }, @@ -194,6 +204,16 @@ }, { "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [115, 125, 150, 150], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [115, 125, 150, 150], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", "rect": [100, 100, 150, 150], "reason": "paint property change" }, @@ -284,6 +304,16 @@ }, { "object": "LayoutBlockFlow div class='innerBox'", + "rect": [440, 150, 100, 100], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow div class='innerBox'", + "rect": [440, 150, 100, 100], + "reason": "geometry" + }, + { + "object": "LayoutBlockFlow div class='innerBox'", "rect": [425, 125, 100, 100], "reason": "geometry" }, @@ -374,6 +404,16 @@ }, { "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [140, 150, 100, 100], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", + "rect": [140, 150, 100, 100], + "reason": "paint property change" + }, + { + "object": "LayoutSVGRoot (positioned) svg id='svg'", "rect": [125, 125, 100, 100], "reason": "paint property change" }
diff --git a/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div.xhtml b/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div.xhtml index 3850746..b5fac673 100644 --- a/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div.xhtml +++ b/third_party/blink/web_tests/paint/invalidation/svg/repaint-moving-svg-and-div.xhtml
@@ -1,5 +1,6 @@ <html xmlns="http://www.w3.org/1999/xhtml"> <head> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/text-based-repaint.js"></script> <style> @@ -86,7 +87,7 @@ htmlStyle.top = htmlTop + "px"; ++iterations; - requestAnimationFrame(repaintTest); + runAfterLayoutAndPaint(repaintTest); } else { finishRepaintTest(); }
diff --git a/third_party/blink/web_tests/paint/invalidation/text-decoration-invalidation.html b/third_party/blink/web_tests/paint/invalidation/text-decoration-invalidation.html index 9d62333..feddcfc 100644 --- a/third_party/blink/web_tests/paint/invalidation/text-decoration-invalidation.html +++ b/third_party/blink/web_tests/paint/invalidation/text-decoration-invalidation.html
@@ -22,15 +22,12 @@ <span>When</span> <span>not hovered, </span><span>there</span> <span>should</span> <span> be </span> <span>no</span> <span>underlines.</span> </div> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> -if (window.testRunner) { - testRunner.waitUntilDone(); - if (window.eventSender); - eventSender.mouseMoveTo(underlineNoHover.offsetLeft + 10, underlineNoHover.offsetTop + 10); - testRunner.layoutAndPaintAsyncThen(function(){ - if (window.eventSender); - eventSender.mouseMoveTo(underlineHover.offsetLeft + 10, underlineHover.offsetTop + 10); - testRunner.notifyDone(); - }); -} -</script> \ No newline at end of file +if (window.eventSender) + eventSender.mouseMoveTo(underlineNoHover.offsetLeft + 10, underlineNoHover.offsetTop + 10); +runAfterLayoutAndPaint(function() { + if (window.eventSender) + eventSender.mouseMoveTo(underlineHover.offsetLeft + 10, underlineHover.offsetTop + 10); +}, true); +</script>
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered-composited.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered-composited.html index 9f8e48b..b44f303 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered-composited.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered-composited.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <script> if (window.internals)
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered.html index 062f9ac..6ba82ac 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-centered.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> body {
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-generated.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-generated.html index e0158c8..cfc9cff5 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-generated.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-generated.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> body {
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-scrolling-contents.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-scrolling-contents.html index 0307d0af..9def798 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-scrolling-contents.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-fixed-scrolling-contents.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> body {
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-non-fixed.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-non-fixed.html index 046c9c6..32b682e 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-non-fixed.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-background-image-non-fixed.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> body {
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos.html index 96f0ab0..12cd01f3 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-centered-inline-under-fixed-pos.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> .container {
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-child-background-image-fixed-centered.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-child-background-image-fixed-centered.html index 97b67ba8..a4573a1 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-child-background-image-fixed-centered.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-child-background-image-fixed-centered.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> #target {
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-frameset.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-frameset.html index 88066c15..192249a0 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-frameset.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-frameset.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <frameset cols="25%,*,25%"> <frame>
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-media-query.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-media-query.html index 35b681fc..fb6a549 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-media-query.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-media-query.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style media="(min-height: 201px)"> body { background-color: blue; }
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change1.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change1.html index 0f3c882..b93d6b0d 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change1.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change1.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> html { overflow: hidden; }
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change2.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change2.html index ed04a5c..1be0a5da 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change2.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-no-layout-change2.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <style> html { overflow: hidden; }
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-html.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-html.html index 873a28c5..f462890 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-html.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-html.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <html style="height: 50%"> <body style="height: 100%; margin: 0">
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-width-height.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-width-height.html index 6a1e1f0..f3d5d9c 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-width-height.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-percent-width-height.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <body style="margin: 0"> <div style="position: absolute; width: 50%; height: 50%; background-color: blue"></div>
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-bottom.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-bottom.html index 74872c5..5b781c9 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-bottom.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-bottom.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <body style="margin: 0"> <div style="position: absolute; width: 20px; height: 20px; bottom: 20px; background-color: blue"></div> -</body> \ No newline at end of file +</body>
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-percent-top.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-percent-top.html index 6f613906..79097ac 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-percent-top.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-positioned-percent-top.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <body style="margin: 0"> <div style="position: absolute; top: 50%; width: 20px; height: 20px; background-color: blue"></div>
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-vertical-writing-mode.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-vertical-writing-mode.html index 2af6f0c6..64e25e1ff 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-vertical-writing-mode.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-vertical-writing-mode.html
@@ -1,5 +1,6 @@ <!DOCTYPE html> <html style="-webkit-writing-mode: vertical-rl"> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <body style="font-size: 60px"> AAAA BBBB CCCC DDDD EEEE FFFF GGGG HHHH IIII JJJJ KKKK LLLL MMMM NNNN
diff --git a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-viewport-percent.html b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-viewport-percent.html index 18bf896..d216e7d 100644 --- a/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-viewport-percent.html +++ b/third_party/blink/web_tests/paint/invalidation/window-resize/window-resize-viewport-percent.html
@@ -1,4 +1,5 @@ <!DOCTYPE html> +<script src="../../../resources/run-after-layout-and-paint.js"></script> <script src="../resources/window-resize-repaint.js"></script> <body style="margin: 0"> <div style="position: absolute">
diff --git a/third_party/blink/web_tests/paint/selection/resources/selection.js b/third_party/blink/web_tests/paint/selection/resources/selection.js index bfc2a447..292e26d 100644 --- a/third_party/blink/web_tests/paint/selection/resources/selection.js +++ b/third_party/blink/web_tests/paint/selection/resources/selection.js
@@ -1,7 +1,7 @@ function selectRangeAfterLayoutAndPaint(startElement, startIndex, endElement, endIndex) { runAfterLayoutAndPaint(function() { selectRange(startElement, startIndex, endElement, endIndex); - }, true); + }, true); } function selectRange(startElement, startIndex, endElement, endIndex) { @@ -15,4 +15,4 @@ var range = document.createRange(); range.selectNode(element); window.getSelection().addRange(range); -} \ No newline at end of file +}
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt index f5c64f2..83570e7 100644 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutTextControl INPUT id='root'", "rect": [0, 0, 61, 22], "reason": "full layer" + }, + { + "object": "Caret", + "rect": [58, 4, 1, 16], + "reason": "caret" } ] }
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt index f5c64f2..83570e7 100644 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutTextControl INPUT id='root'", "rect": [0, 0, 61, 22], "reason": "full layer" + }, + { + "object": "Caret", + "rect": [58, 4, 1, 16], + "reason": "caret" } ] }
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt index cc0c514..09a0829d 100644 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -31,6 +31,11 @@ "object": "LayoutBlockFlow DIV", "rect": [10, 11, 56, 16], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [18, 11, 26, 16], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt index f7a54884..e144691 100644 --- a/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/linux/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -26,6 +26,11 @@ "object": "LayoutBlockFlow DIV", "rect": [10, 11, 57, 16], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [31, 11, 26, 16], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt index ae51837..f1d0681 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -26,6 +26,11 @@ "object": "LayoutBlockFlow DIV", "rect": [11, 11, 35, 13], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [11, 11, 15, 13], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt new file mode 100644 index 0000000..6b51b7d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -0,0 +1,39 @@ +{ + "layers": [ + { + "name": "LayoutView #document", + "bounds": [800, 600], + "drawsContent": false, + "backgroundColor": "#FFFFFF" + }, + { + "name": "Scrolling Layer", + "bounds": [800, 600], + "drawsContent": false + }, + { + "name": "Scrolling Contents Layer", + "bounds": [800, 600], + "contentsOpaque": true, + "backgroundColor": "#FFFFFF", + "paintInvalidations": [ + { + "object": "LayoutTextControl INPUT id='target'", + "rect": [5, 5, 47, 25], + "reason": "subtree" + }, + { + "object": "LayoutBlockFlow DIV", + "rect": [11, 11, 35, 13], + "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [28, 11, 18, 13], + "reason": "selection" + } + ] + } + ] +} +
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png new file mode 100644 index 0000000..764dc14 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png new file mode 100644 index 0000000..4afd29cd --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png new file mode 100644 index 0000000..d82dd1c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png new file mode 100644 index 0000000..1ca9543 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png new file mode 100644 index 0000000..1027048 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png new file mode 100644 index 0000000..aae62e6e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png new file mode 100644 index 0000000..db9466d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png new file mode 100644 index 0000000..764dc14 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png new file mode 100644 index 0000000..4afd29cd --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png new file mode 100644 index 0000000..d82dd1c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png new file mode 100644 index 0000000..1ca9543 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png new file mode 100644 index 0000000..1027048 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png new file mode 100644 index 0000000..aae62e6e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png new file mode 100644 index 0000000..db9466d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png new file mode 100644 index 0000000..764dc14 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png new file mode 100644 index 0000000..4afd29cd --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png new file mode 100644 index 0000000..d82dd1c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png new file mode 100644 index 0000000..1ca9543 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png new file mode 100644 index 0000000..1027048 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png new file mode 100644 index 0000000..aae62e6e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png new file mode 100644 index 0000000..db9466d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png new file mode 100644 index 0000000..764dc14 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png new file mode 100644 index 0000000..4afd29cd --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png new file mode 100644 index 0000000..d82dd1c --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png new file mode 100644 index 0000000..1ca9543 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png new file mode 100644 index 0000000..1027048 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png new file mode 100644 index 0000000..aae62e6e --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png new file mode 100644 index 0000000..db9466d --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt index c0ef892..b5b2bfb9 100644 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutTextControl INPUT id='root'", "rect": [0, 0, 41, 19], "reason": "full layer" + }, + { + "object": "Caret", + "rect": [39, 6, 1, 13], + "reason": "caret" } ] }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt index c0ef892..b5b2bfb9 100644 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutTextControl INPUT id='root'", "rect": [0, 0, 41, 19], "reason": "full layer" + }, + { + "object": "Caret", + "rect": [39, 6, 1, 13], + "reason": "caret" } ] }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt index 674f7f3..1b536cb 100644 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -31,6 +31,11 @@ "object": "LayoutBlockFlow DIV", "rect": [11, 11, 34, 13], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [11, 11, 14, 13], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt index ae51837..cecda7d 100644 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -26,6 +26,11 @@ "object": "LayoutBlockFlow DIV", "rect": [11, 11, 35, 13], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [29, 11, 17, 13], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt b/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt index f912a02..a9f775b 100644 --- a/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt +++ b/third_party/blink/web_tests/platform/mac/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt
@@ -23,11 +23,31 @@ "reason": "appeared" }, { + "object": "InlineTextBox ' B C'", + "rect": [23, 8, 85, 24], + "reason": "appeared" + }, + { + "object": "InlineTextBox ' B C'", + "rect": [23, 8, 85, 24], + "reason": "disappeared" + }, + { "object": "InlineTextBox 'A'", "rect": [23, 8, 85, 24], "reason": "appeared" }, { + "object": "InlineTextBox 'A'", + "rect": [23, 8, 85, 24], + "reason": "appeared" + }, + { + "object": "InlineTextBox 'A'", + "rect": [23, 8, 85, 24], + "reason": "disappeared" + }, + { "object": "InlineTextBox ' B C'", "rect": [23, 8, 80, 24], "reason": "disappeared"
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png index bf57eca..764dc14 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png new file mode 100644 index 0000000..4afd29cd --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-in-positioned-container-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png index fa4f8c7..d82dd1c 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-outline-color-not-inherited-from-map-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png index 1566267..1ca9543 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-with-paint-root-offset-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png index e311764..1027048 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-focus-ring-zoom-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png index 25c4a6a..aae62e6e 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-overflowing-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png index e86ef63d..db9466d 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu-rasterization/images/imagemap-polygon-focus-ring-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt index 1a1be903..b2c5d38 100644 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutTextControl INPUT id='root'", "rect": [0, 0, 68, 22], "reason": "full layer" + }, + { + "object": "Caret", + "rect": [65, 4, 1, 16], + "reason": "caret" } ] }
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt index 1a1be903..b2c5d38 100644 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/win/paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -32,6 +32,11 @@ "object": "LayoutTextControl INPUT id='root'", "rect": [0, 0, 68, 22], "reason": "full layer" + }, + { + "object": "Caret", + "rect": [65, 4, 1, 16], + "reason": "caret" } ] }
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt index 671c110..986b7789 100644 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-composited-scrolling-container-expected.txt
@@ -31,6 +31,11 @@ "object": "LayoutBlockFlow DIV", "rect": [10, 11, 63, 16], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [25, 11, 26, 16], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt index 3ee964e..5def703 100644 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt +++ b/third_party/blink/web_tests/platform/win/paint/invalidation/selection/selection-in-non-composited-scrolling-container-expected.txt
@@ -26,6 +26,11 @@ "object": "LayoutBlockFlow DIV", "rect": [10, 11, 64, 16], "reason": "paint property change" + }, + { + "object": "InlineTextBox 'test test test'", + "rect": [31, 11, 26, 16], + "reason": "selection" } ] }
diff --git a/third_party/blink/web_tests/platform/win/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt b/third_party/blink/web_tests/platform/win/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt index 5dea806fb..59f8f6dc 100644 --- a/third_party/blink/web_tests/platform/win/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt +++ b/third_party/blink/web_tests/platform/win/paint/invalidation/svg/modify-transferred-listitem-different-attr-expected.txt
@@ -23,11 +23,31 @@ "reason": "appeared" }, { + "object": "InlineTextBox ' B C'", + "rect": [23, 8, 85, 23], + "reason": "appeared" + }, + { + "object": "InlineTextBox ' B C'", + "rect": [23, 8, 85, 23], + "reason": "disappeared" + }, + { "object": "InlineTextBox 'A'", "rect": [23, 8, 85, 23], "reason": "appeared" }, { + "object": "InlineTextBox 'A'", + "rect": [23, 8, 85, 23], + "reason": "appeared" + }, + { + "object": "InlineTextBox 'A'", + "rect": [23, 8, 85, 23], + "reason": "disappeared" + }, + { "object": "InlineTextBox ' B C'", "rect": [23, 8, 80, 23], "reason": "disappeared"
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png new file mode 100644 index 0000000..7bad532 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-arc-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png new file mode 100644 index 0000000..982bd43 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png index 540a17bf..1464101 100644 --- a/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png +++ b/third_party/blink/web_tests/platform/win7/virtual/gpu/fast/canvas/canvas-ellipse-circumference-fill-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/resources/run-after-layout-and-paint.js b/third_party/blink/web_tests/resources/run-after-layout-and-paint.js index e317341..bf2ed0c 100644 --- a/third_party/blink/web_tests/resources/run-after-layout-and-paint.js +++ b/third_party/blink/web_tests/resources/run-after-layout-and-paint.js
@@ -1,26 +1,34 @@ -// Run a callback after layout and paint of all pending document changes. +// Run a callback after a frame update. // -// It has two modes: -// - traditional mode, for existing tests, and tests needing customized notifyDone timing: -// Usage: +// Note that this file has two copies: +// resources/run-after-layout-and-paint.js +// and +// http/tests/resources/run-after-layout-and-paint.js. +// They should be kept always the same. +// +// The function runAfterLayoutAndPaint() has two modes: +// - traditional mode, for existing tests, and tests needing customized +// notifyDone timing: // if (window.testRunner) // testRunner.waitUntilDone(); // runAfterLayoutAndPaint(function() { // ... // some code which modifies style/layout // if (window.testRunner) // testRunner.notifyDone(); -// // Or to ensure the next paint is executed before the test finishes: -// // if (window.testRunner) -// // runAfterAfterLayoutAndPaint(function() { testRunner.notifyDone() }); // // Or notifyDone any time later if needed. // }); // -// - autoNotifyDone mode, for new tests which just need to change style/layout and finish: -// Usage: +// - autoNotifyDone mode, for new tests which just need to change style/layout +// and finish: // runAfterLayoutAndPaint(function() { // ... // some code which modifies style/layout // }, true); - +// +// Note that because we always update a frame before finishing a test, +// we don't need +// runAfterLayoutAndPaint(function() { testRunner.notifyDone(); }) +// to ensure the test finish after a frame update. +// if (window.internals) internals.runtimeFlags.paintUnderInvalidationCheckingEnabled = true; @@ -35,9 +43,18 @@ if (autoNotifyDone) testRunner.waitUntilDone(); - testRunner.layoutAndPaintAsyncThen(function() { - callback(); - if (autoNotifyDone) - testRunner.notifyDone(); + // We do requestAnimationFrame and setTimeout to ensure a frame has started + // and layout and paint have run. The requestAnimationFrame fires after the + // frame has started but before layout and paint. The setTimeout fires + // at the beginning of the next frame, meaning that the previous frame has + // completed layout and paint. + // See http://crrev.com/c/1395193/10/third_party/blink/web_tests/http/tests/resources/run-after-layout-and-paint.js + // for more discussions. + requestAnimationFrame(function() { + setTimeout(function() { + callback(); + if (autoNotifyDone) + testRunner.notifyDone(); + }, 0); }); }
diff --git a/third_party/blink/web_tests/svg/animations/animate-restart-never.html b/third_party/blink/web_tests/svg/animations/animate-restart-never.html index 7f8127fc..743df85 100644 --- a/third_party/blink/web_tests/svg/animations/animate-restart-never.html +++ b/third_party/blink/web_tests/svg/animations/animate-restart-never.html
@@ -13,11 +13,7 @@ function animationEnded() { click(50,50); - if (window.testRunner) { - testRunner.layoutAndPaintAsyncThen(function() { - testRunner.notifyDone(); - }); - } + testRunner.notifyDone(); } </script> <svg>
diff --git a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-1.html b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-1.html index dbe549f6..14b80064 100644 --- a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-1.html +++ b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-1.html
@@ -1,18 +1,11 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.dumpAsText(); - testRunner.waitUntilDone(); window.onload = function() { - testRunner.layoutAndPaintAsyncThen(function() { - mutateTree(); - testRunner.layoutAndPaintAsyncThen(function() { - testRunner.notifyDone(); - }); - }); + runAfterLayoutAndPaint(mutateTree, true); }; -} else { - window.onload = function() { setTimeout(mutateTree, 100); }; } function mutateTree() { // A reference from the 'rect' to the pattern cycle.
diff --git a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-2.html b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-2.html index 84175b1..5060ecd6 100644 --- a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-2.html +++ b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-2.html
@@ -1,18 +1,11 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.dumpAsText(); - testRunner.waitUntilDone(); window.onload = function() { - testRunner.layoutAndPaintAsyncThen(function() { - mutateTree(); - testRunner.layoutAndPaintAsyncThen(function() { - testRunner.notifyDone(); - }); - }); + runAfterLayoutAndPaint(mutateTree, true); }; -} else { - window.onload = function() { setTimeout(mutateTree, 100); }; } function mutateTree() { // Add a reference from the rect in pattern#p3 to form a cycle.
diff --git a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-3.html b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-3.html index 58325935..ad7cb352 100644 --- a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-3.html +++ b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-3.html
@@ -1,18 +1,11 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.dumpAsText(); - testRunner.waitUntilDone(); window.onload = function() { - testRunner.layoutAndPaintAsyncThen(function() { - mutateTree(); - testRunner.layoutAndPaintAsyncThen(function() { - testRunner.notifyDone(); - }); - }); + runAfterLayoutAndPaint(mutateTree, true); }; -} else { - window.onload = function() { setTimeout(mutateTree, 100); }; } const svgNs = 'http://www.w3.org/2000/svg'; function buildPattern(patternId, refId) {
diff --git a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-4.html b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-4.html index b053b48..5308106 100644 --- a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-4.html +++ b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle-dynamic-4.html
@@ -1,18 +1,11 @@ <!DOCTYPE html> +<script src="../../resources/run-after-layout-and-paint.js"></script> <script> if (window.testRunner) { testRunner.dumpAsText(); - testRunner.waitUntilDone(); window.onload = function() { - testRunner.layoutAndPaintAsyncThen(function() { - mutateTree(); - testRunner.layoutAndPaintAsyncThen(function() { - testRunner.notifyDone(); - }); - }); + runAfterLayoutAndPaint(mutateTree, true); }; -} else { - window.onload = function() { setTimeout(mutateTree, 100); }; } const svgNs = 'http://www.w3.org/2000/svg'; function buildPattern(patternId, refId) {
diff --git a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle.html b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle.html index 6356e35..619ce00 100644 --- a/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle.html +++ b/third_party/blink/web_tests/svg/custom/pattern-3-step-cycle.html
@@ -1,12 +1,7 @@ <!DOCTYPE html> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.dumpAsText(); - testRunner.waitUntilDone(); - window.onload = function() { - testRunner.layoutAndPaintAsyncThen(function() { testRunner.notifyDone(); }); - }; -} </script> <p>PASS if no crash (stack overflow).</p> <svg width="100" height="100">
diff --git a/third_party/blink/web_tests/svg/custom/pattern-content-cycle-w-resourceless-container.html b/third_party/blink/web_tests/svg/custom/pattern-content-cycle-w-resourceless-container.html index b15db7065..53c91cd 100644 --- a/third_party/blink/web_tests/svg/custom/pattern-content-cycle-w-resourceless-container.html +++ b/third_party/blink/web_tests/svg/custom/pattern-content-cycle-w-resourceless-container.html
@@ -1,12 +1,7 @@ <!DOCTYPE html> <script> -if (window.testRunner) { +if (window.testRunner) testRunner.dumpAsText(); - testRunner.waitUntilDone(); - window.onload = function() { - testRunner.layoutAndPaintAsyncThen(function() { testRunner.notifyDone(); }); - }; -} </script> <p>PASS if no crash (stack overflow).</p> <svg width="100" height="100">
diff --git a/third_party/blink/web_tests/svg/custom/svg-image-container-size.html b/third_party/blink/web_tests/svg/custom/svg-image-container-size.html index 772220b..d896df6 100644 --- a/third_party/blink/web_tests/svg/custom/svg-image-container-size.html +++ b/third_party/blink/web_tests/svg/custom/svg-image-container-size.html
@@ -19,10 +19,7 @@ } function startTest() { - if (window.testRunner) - testRunner.layoutAndPaintAsyncThen(insertSVGImage); - else - requestAnimationFrame(insertSVGImage); + runAfterLayoutAndPaint(insertSVGImage); } </script> <svg width="384" height="128" style="display: block">
diff --git a/third_party/closure_compiler/externs/accessibility_private.js b/third_party/closure_compiler/externs/accessibility_private.js index bf119ed..380b987 100644 --- a/third_party/closure_compiler/externs/accessibility_private.js +++ b/third_party/closure_compiler/externs/accessibility_private.js
@@ -180,6 +180,12 @@ chrome.accessibilityPrivate.setSwitchAccessMenuState = function(show, element_bounds) {}; /** + * When enabled, forwards key events to the Switch Access extension. + * @param {boolean} should_forward + */ +chrome.accessibilityPrivate.forwardKeyEventsToSwitchAccess = function(should_forward) {}; + +/** * Sets current ARC app to use native ARC support. * @param {boolean} enabled True for ChromeVox (native), false for TalkBack. */
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index fda5e99..3c1138fd 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -11516,6 +11516,11 @@ <description>User pressed 'Scan QR Code' in the app menu.</description> </action> +<action name="MobileMenuSearchCopiedImage"> + <owner>rkgibson@google.com</owner> + <description>User pressed 'Search Copied Image' in the app menu.</description> +</action> + <action name="MobileMenuSettings"> <owner>aurimas@chromium.org</owner> <description>User pressed 'Settings' in the app menu.</description>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 4f67b80e..f6d79bb 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -3534,6 +3534,7 @@ <int value="15" label="Component update task"/> <int value="16" label="Deprecated Explore Sites refresh task"/> <int value="17" label="Explore Sites refresh task"/> + <int value="18" label="Download auto-resumption task"/> </enum> <enum name="BackgroundTracingState"> @@ -17624,6 +17625,8 @@ <int value="1305" label="AUTOTESTPRIVATE_SENDASSISTANTTEXTQUERY"/> <int value="1306" label="AUTOTESTPRIVATE_SETCROSTINIAPPSCALED"/> <int value="1307" label="ACTIVITYLOGPRIVATE_DELETEACTIVITIESBYEXTENSION"/> + <int value="1308" + label="ACCESSIBILITY_PRIVATE_FORWARDKEYEVENTSTOSWITCHACCESS"/> </enum> <enum name="ExtensionIconState"> @@ -26702,7 +26705,7 @@ </enum> <enum name="IDBLevelDBBackingStoreOpenResult"> - <int value="0" label="OpenMemorySuccess"> + <int value="0" label="OpenMemorySuccess (Deprecated)"> An in-memory backing store was opened successfully. </int> <int value="1" label="OpenSuccess"> @@ -26734,7 +26737,7 @@ version. </int> <int value="8" label="OpenFailedUnknownErr"/> - <int value="9" label="OpenMemoryFailed"> + <int value="9" label="OpenMemoryFailed (Deprecated)"> An in-memory backing store failed to open. </int> <int value="10" label="OpenNonASCII">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index e061c24..953f3360 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -123650,6 +123650,9 @@ <histogram name="WebCore.IndexedDB.LevelDB.FreeDiskSpaceFailure" enum="LevelDBErrorCount"> + <obsolete> + Deprecated 1/19. Metric never actually worked, as -1 / 1024 yields 0. + </obsolete> <owner>dgrogan@chromium.org</owner> <summary> Count of how many times LevelDBDatabase got an error trying to check free @@ -123658,6 +123661,9 @@ </histogram> <histogram name="WebCore.IndexedDB.LevelDB.OpenFailureFreeDiskSpace" units="Kb"> + <obsolete> + Deprecated 1/19. Use Quota.AvailableDiskSpace instead. + </obsolete> <owner>dgrogan@chromium.org</owner> <summary> Amount of free disk space on the partition/volume/etc where LevelDB failed @@ -123666,6 +123672,9 @@ </histogram> <histogram name="WebCore.IndexedDB.LevelDB.OpenSuccessFreeDiskSpace" units="Kb"> + <obsolete> + Deprecated 1/19. Use Quota.AvailableDiskSpace instead. + </obsolete> <owner>dgrogan@chromium.org</owner> <summary> Amount of free disk space on the partition/volume/etc where LevelDB was
diff --git a/ui/accessibility/ax_node.cc b/ui/accessibility/ax_node.cc index 13f5765..ce1088f 100644 --- a/ui/accessibility/ax_node.cc +++ b/ui/accessibility/ax_node.cc
@@ -357,6 +357,33 @@ return 0; } +#if defined(OS_MACOSX) +// +// Table column-like nodes. These nodes are only present on macOS. +// + +bool AXNode::IsTableColumn() const { + return data().role == ax::mojom::Role::kColumn; +} + +int32_t AXNode::GetTableColColIndex() const { + if (!IsTableColumn()) + return 0; + + AXTableInfo* table_info = GetAncestorTableInfo(); + if (!table_info) + return 0; + + int32_t index = 0; + for (const AXNode* node : table_info->extra_mac_nodes) { + if (node == this) + break; + index++; + } + return index; +} +#endif // defined(OS_MACOSX) + // // Table cell-like nodes. // @@ -519,12 +546,21 @@ } } +// Uses function in ax_role_properties to check if node is item-like. +bool AXNode::IsOrderedSetItem() const { + return ui::IsItemLike(data().role); +} +// Uses function in ax_role_properties to check if node is oredered-set-like. +bool AXNode::IsOrderedSet() const { + return ui::IsSetLike(data().role); +} + // pos_in_set and set_size related functions. // Uses AXTree's cache to calculate node's pos_in_set. int32_t AXNode::GetPosInSet() { // Only allow this to be called on nodes that can hold pos_in_set values, // which are defined in the ARIA spec. - if (!IsItemLike(data().role)) { + if (!IsOrderedSetItem()) { return 0; } @@ -541,7 +577,7 @@ int32_t AXNode::GetSetSize() { // Only allow this to be called on nodes that can hold set_size values, which // are defined in the ARIA spec. - if (!(IsItemLike(data().role) || IsSetLike(data().role))) + if (!(IsOrderedSetItem() || IsOrderedSet())) return 0; // If node is item-like, find its outerlying ordered set. Otherwise,
diff --git a/ui/accessibility/ax_node.h b/ui/accessibility/ax_node.h index 5443831..d23a52d 100644 --- a/ui/accessibility/ax_node.h +++ b/ui/accessibility/ax_node.h
@@ -11,6 +11,7 @@ #include <ostream> #include <vector> +#include "build/build_config.h" #include "ui/accessibility/ax_export.h" #include "ui/accessibility/ax_node_data.h" @@ -188,7 +189,9 @@ return data().GetHtmlAttribute(attribute, value); } - // PosInSet and SetSize public methods + // PosInSet and SetSize public methods. + bool IsOrderedSetItem() const; + bool IsOrderedSet() const; int32_t GetPosInSet(); int32_t GetSetSize(); @@ -249,6 +252,12 @@ bool IsTableRow() const; int32_t GetTableRowRowIndex() const; +#if defined(OS_MACOSX) + // Table column-like nodes. These nodes are only present on macOS. + bool IsTableColumn() const; + int32_t GetTableColColIndex() const; +#endif // defined(OS_MACOSX) + // Table cell-like nodes. bool IsTableCellOrHeader() const; int32_t GetTableCellIndex() const;
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc index 9c53b19e..b277f70 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -589,11 +589,6 @@ ax::mojom::IntAttribute::kHierarchicalLevel, "level"); TestAtkObjectIntAttribute(root_node, root_atk_object, - ax::mojom::IntAttribute::kSetSize, "setsize"); - TestAtkObjectIntAttribute(root_node, root_atk_object, - ax::mojom::IntAttribute::kPosInSet, "posinset"); - - TestAtkObjectIntAttribute(root_node, root_atk_object, ax::mojom::IntAttribute::kAriaColumnCount, "colcount", ax::mojom::Role::kTable); TestAtkObjectIntAttribute(root_node, root_atk_object, @@ -1277,4 +1272,55 @@ g_object_unref(root_atk_object); } +// Tests GetPosInSet() and GetSetSize() functions of AXPlatformNodeBase. +// PosInSet and SetSize must be tested separately from other IntAttributes +// because they can be either assigned values or calculated dynamically. +TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkObjectSetSizePosInSet) { + AXTreeUpdate update; + update.root_id = 1; + update.nodes.resize(4); + update.nodes[0].id = 1; + update.nodes[0].role = ax::mojom::Role::kRadioGroup; + update.nodes[0].child_ids = {2, 3, 4}; + update.nodes[1].id = 2; + update.nodes[1].role = + ax::mojom::Role::kRadioButton; // kRadioButton posinset = 2, setsize = 5. + update.nodes[1].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 2); + update.nodes[2].id = 3; + update.nodes[2].role = + ax::mojom::Role::kRadioButton; // kRadioButton posinset = 3, setsize = 5. + update.nodes[3].id = 4; + update.nodes[3].role = + ax::mojom::Role::kRadioButton; // kRadioButton posinset = 5, stesize = 5 + update.nodes[3].AddIntAttribute(ax::mojom::IntAttribute::kPosInSet, 5); + Init(update); + + AXNode* radiobutton1 = GetRootNode()->children()[0]; + AtkObject* radiobutton1_atk_object(AtkObjectFromNode(radiobutton1)); + EXPECT_TRUE(ATK_IS_OBJECT(radiobutton1_atk_object)); + g_object_ref(radiobutton1_atk_object); + + AXNode* radiobutton2 = GetRootNode()->children()[1]; + AtkObject* radiobutton2_atk_object(AtkObjectFromNode(radiobutton2)); + EXPECT_TRUE(ATK_IS_OBJECT(radiobutton2_atk_object)); + g_object_ref(radiobutton2_atk_object); + + AXNode* radiobutton3 = GetRootNode()->children()[2]; + AtkObject* radiobutton3_atk_object(AtkObjectFromNode(radiobutton3)); + EXPECT_TRUE(ATK_IS_OBJECT(radiobutton3_atk_object)); + g_object_ref(radiobutton3_atk_object); + + // Notice that setsize was never assigned to any of the kRadioButtons, but was + // inferred. + EnsureAtkObjectHasAttributeWithValue(radiobutton1_atk_object, "posinset", + "2"); + EnsureAtkObjectHasAttributeWithValue(radiobutton1_atk_object, "setsize", "5"); + EnsureAtkObjectHasAttributeWithValue(radiobutton2_atk_object, "posinset", + "3"); + EnsureAtkObjectHasAttributeWithValue(radiobutton2_atk_object, "setsize", "5"); + EnsureAtkObjectHasAttributeWithValue(radiobutton3_atk_object, "posinset", + "5"); + EnsureAtkObjectHasAttributeWithValue(radiobutton3_atk_object, "setsize", "5"); +} + } // namespace ui
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index 24f9d1e..7d9ffb2 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -915,6 +915,7 @@ const char* name, PlatformAttributeList* attributes) { DCHECK(attributes); + auto maybe_value = ComputeAttribute(delegate_, attribute); if (maybe_value.has_value()) { std::string str_value = base::IntToString(maybe_value.value());
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h index 0b40d2a..f569559 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate.h +++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -146,7 +146,9 @@ virtual int32_t GetCellId(int32_t row_index, int32_t col_index) const = 0; virtual int32_t CellIndexToId(int32_t cell_index) const = 0; - // Only called on ordered-set-like elements and item-like elements. + // Ordered-set-like and item-like nodes. + virtual bool IsOrderedSetItem() const = 0; + virtual bool IsOrderedSet() const = 0; virtual int32_t GetPosInSet() const = 0; virtual int32_t GetSetSize() const = 0;
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc index 2314a13..d1aa8dbd 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc +++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -193,6 +193,14 @@ return *dummy_unique_id; } +bool AXPlatformNodeDelegateBase::IsOrderedSetItem() const { + return false; +} + +bool AXPlatformNodeDelegateBase::IsOrderedSet() const { + return false; +} + int32_t AXPlatformNodeDelegateBase::GetPosInSet() const { return 0; }
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h index 80ab923..20a2c999 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate_base.h +++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -121,7 +121,9 @@ int32_t GetCellId(int32_t row_index, int32_t col_index) const override; int32_t CellIndexToId(int32_t cell_index) const override; - // Only called on ordered-set-like elements and item-like elements. + // Ordered-set-like and item-like nodes. + bool IsOrderedSetItem() const override; + bool IsOrderedSet() const override; int32_t GetPosInSet() const override; int32_t GetSetSize() const override;
diff --git a/ui/accessibility/platform/compute_attributes.cc b/ui/accessibility/platform/compute_attributes.cc index 3531a2e..1b04e0e 100644 --- a/ui/accessibility/platform/compute_attributes.cc +++ b/ui/accessibility/platform/compute_attributes.cc
@@ -61,6 +61,35 @@ } } +base::Optional<int32_t> GetOrderedSetItemAttribute( + const ui::AXPlatformNodeDelegate* delegate, + ax::mojom::IntAttribute attribute) { + int value = 0; + switch (attribute) { + case ax::mojom::IntAttribute::kPosInSet: + value = delegate->GetPosInSet(); + return value; + case ax::mojom::IntAttribute::kSetSize: + value = delegate->GetSetSize(); + return value; + default: + return base::nullopt; + } +} + +base::Optional<int32_t> GetOrderedSetAttribute( + const ui::AXPlatformNodeDelegate* delegate, + ax::mojom::IntAttribute attribute) { + int value = 0; + switch (attribute) { + case ax::mojom::IntAttribute::kSetSize: + value = delegate->GetSetSize(); + return value; + default: + return base::nullopt; + } +} + base::Optional<int32_t> GetFromData(const ui::AXPlatformNodeDelegate* delegate, ax::mojom::IntAttribute attribute) { int32_t value; @@ -76,12 +105,18 @@ const ui::AXPlatformNodeDelegate* delegate, ax::mojom::IntAttribute attribute) { base::Optional<int32_t> maybe_value = base::nullopt; + // Table-related nodes. if (delegate->IsTableCellOrHeader()) maybe_value = GetCellAttribute(delegate, attribute); else if (delegate->IsTableRow()) maybe_value = GetRowAttribute(delegate, attribute); else if (delegate->IsTable()) maybe_value = GetTableAttribute(delegate, attribute); + // Ordered-set-related nodes. + else if (delegate->IsOrderedSetItem()) + maybe_value = GetOrderedSetItemAttribute(delegate, attribute); + else if (delegate->IsOrderedSet()) + maybe_value = GetOrderedSetAttribute(delegate, attribute); if (!maybe_value.has_value()) { return GetFromData(delegate, attribute);
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.cc b/ui/accessibility/platform/test_ax_node_wrapper.cc index 292c019..f3462d8 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.cc +++ b/ui/accessibility/platform/test_ax_node_wrapper.cc
@@ -307,6 +307,14 @@ platform_node_(AXPlatformNode::Create(this)) { } +bool TestAXNodeWrapper::IsOrderedSetItem() const { + return node_->IsOrderedSetItem(); +} + +bool TestAXNodeWrapper::IsOrderedSet() const { + return node_->IsOrderedSet(); +} + int32_t TestAXNodeWrapper::GetPosInSet() const { return node_->GetPosInSet(); }
diff --git a/ui/accessibility/platform/test_ax_node_wrapper.h b/ui/accessibility/platform/test_ax_node_wrapper.h index eb29fb0..726bb41 100644 --- a/ui/accessibility/platform/test_ax_node_wrapper.h +++ b/ui/accessibility/platform/test_ax_node_wrapper.h
@@ -57,7 +57,8 @@ int32_t dst_id) override; std::set<int32_t> GetReverseRelations(ax::mojom::IntListAttribute attr, int32_t dst_id) override; - + bool IsOrderedSetItem() const override; + bool IsOrderedSet() const override; int32_t GetPosInSet() const override; int32_t GetSetSize() const override;
diff --git a/ui/base/material_design/material_design_controller.cc b/ui/base/material_design/material_design_controller.cc index e9700d21..da5ffa6 100644 --- a/ui/base/material_design/material_design_controller.cc +++ b/ui/base/material_design/material_design_controller.cc
@@ -20,8 +20,6 @@ #include "ui/base/ui_base_switches.h" #include "ui/base/ui_features.h" #include "ui/gfx/animation/linear_animation.h" -#include "ui/gfx/color_palette.h" -#include "ui/gfx/color_utils.h" #if defined(OS_WIN) #include "base/win/win_util.h" @@ -87,11 +85,8 @@ } SetTouchUi(touch); - // Ideally, there would be a more general, "initialize random stuff here" - // function into which these things and a call to this function can be placed. - // TODO(crbug.com/864544) - color_utils::SetDarkestColor(gfx::kGoogleGrey900); - + // TODO(crbug.com/864544): Ideally, there would be a more general, "initialize + // random stuff here" function into which this sort of thing can be placed. double animation_duration_scale; if (base::StringToDouble( command_line->GetSwitchValueASCII(switches::kAnimationDurationScale),
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc index 9edd09b..afcd749 100644 --- a/ui/gfx/color_utils.cc +++ b/ui/gfx/color_utils.cc
@@ -28,10 +28,14 @@ namespace { // The darkest reference color in color_utils. -SkColor g_color_utils_darkest = SK_ColorBLACK; +SkColor g_darkest_color = gfx::kGoogleGrey900; -// The luma midpoint for determining if a color is light or dark. -int g_color_utils_luma_midpoint = 128; +// The luminance midpoint for determining if a color is light or dark. This is +// the value where white and g_darkest_color contrast equally. This default +// value is the midpoint given kGoogleGrey900 as the darkest color. +float g_luminance_midpoint = 0.211692036f; + +constexpr float kWhiteLuminance = 1.0f; int calcHue(float temp1, float temp2, float hue) { if (hue < 0.0f) @@ -300,12 +304,12 @@ } bool IsDark(SkColor color) { - return GetLuma(color) < g_color_utils_luma_midpoint; + return GetRelativeLuminance(color) < g_luminance_midpoint; } SkColor BlendTowardOppositeLuma(SkColor color, SkAlpha alpha) { - return AlphaBlend(IsDark(color) ? SK_ColorWHITE : g_color_utils_darkest, - color, alpha); + return AlphaBlend(IsDark(color) ? SK_ColorWHITE : g_darkest_color, color, + alpha); } SkColor GetThemedAssetColor(SkColor theme_color) { @@ -343,7 +347,7 @@ SkColor GetColorWithMinimumContrast(SkColor default_foreground, SkColor background) { const SkColor blend_direction = - IsDark(background) ? SK_ColorWHITE : g_color_utils_darkest; + BlendTowardOppositeLuma(background, SK_AlphaOPAQUE); const SkAlpha alpha = GetBlendValueWithMinimumContrast( default_foreground, blend_direction, background, kMinimumReadableContrastRatio); @@ -438,13 +442,24 @@ SkColorGetB(color)); } -void SetDarkestColor(SkColor color) { - g_color_utils_darkest = color; - g_color_utils_luma_midpoint = (GetLuma(color) + 255) / 2; +SkColor SetDarkestColorForTesting(SkColor color) { + const SkColor previous_darkest_color = g_darkest_color; + g_darkest_color = color; + + const float dark_luminance = GetRelativeLuminance(color); + // We want to compute |g_luminance_midpoint| such that + // GetContrastRatio(dark_luminance, g_luminance_midpoint) == + // GetContrastRatio(kWhiteLuminance, g_luminance_midpoint). The formula below + // can be verified by plugging it into how GetContrastRatio() operates. + g_luminance_midpoint = + std::sqrtf((dark_luminance + 0.05f) * (kWhiteLuminance + 0.05f)) - 0.05f; + + return previous_darkest_color; } -SkColor GetDarkestColor() { - return g_color_utils_darkest; +std::tuple<float, float, float> GetLuminancesForTesting() { + return std::make_tuple(GetRelativeLuminance(g_darkest_color), + g_luminance_midpoint, kWhiteLuminance); } } // namespace color_utils
diff --git a/ui/gfx/color_utils.h b/ui/gfx/color_utils.h index 80b3504..7e5612c 100644 --- a/ui/gfx/color_utils.h +++ b/ui/gfx/color_utils.h
@@ -6,6 +6,7 @@ #define UI_GFX_COLOR_UTILS_H_ #include <string> +#include <tuple> #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/gfx_export.h" @@ -105,7 +106,7 @@ GFX_EXPORT SkColor GetResultingPaintColor(SkColor foreground, SkColor background); -// Returns true if the luma of |color| is closer to black than white. +// Returns true if |color| contrasts more with white than the darkest color. GFX_EXPORT bool IsDark(SkColor color); // Makes a dark color lighter or a light color darker by blending |color| with @@ -185,11 +186,12 @@ // Creates an rgb string for an SkColor. For example: '255,0,255'. GFX_EXPORT std::string SkColorToRgbString(SkColor color); -// Sets the color_utils darkest color to |color| from the SK_ColorBLACK default. -GFX_EXPORT void SetDarkestColor(SkColor color); +// Sets the darkest available color to |color|. Returns the previous darkest +// color. +GFX_EXPORT SkColor SetDarkestColorForTesting(SkColor color); -// Returns the current color_utils darkest color so tests can clean up. -GFX_EXPORT SkColor GetDarkestColor(); +// Returns the luminance of the darkest, midpoint, and lightest colors. +GFX_EXPORT std::tuple<float, float, float> GetLuminancesForTesting(); } // namespace color_utils
diff --git a/ui/gfx/color_utils_unittest.cc b/ui/gfx/color_utils_unittest.cc index bb39cacb..3e026be 100644 --- a/ui/gfx/color_utils_unittest.cc +++ b/ui/gfx/color_utils_unittest.cc
@@ -205,13 +205,25 @@ } TEST(ColorUtils, IsDarkDarkestColorChange) { - SkColor old_black_color = GetDarkestColor(); - ASSERT_FALSE(IsDark(SkColorSetARGB(255, 200, 200, 200))); - SetDarkestColor(SkColorSetARGB(255, 200, 200, 200)); + const SkColor old_darkest_color = + SetDarkestColorForTesting(SkColorSetARGB(255, 200, 200, 200)); EXPECT_TRUE(IsDark(SkColorSetARGB(255, 200, 200, 200))); - SetDarkestColor(old_black_color); + SetDarkestColorForTesting(old_darkest_color); +} + +TEST(ColorUtils, MidpointLuminanceMatches) { + const SkColor old_darkest_color = SetDarkestColorForTesting(SK_ColorBLACK); + float darkest, midpoint, lightest; + std::tie(darkest, midpoint, lightest) = GetLuminancesForTesting(); + EXPECT_FLOAT_EQ(GetContrastRatio(darkest, midpoint), + GetContrastRatio(midpoint, lightest)); + + SetDarkestColorForTesting(old_darkest_color); + std::tie(darkest, midpoint, lightest) = GetLuminancesForTesting(); + EXPECT_FLOAT_EQ(GetContrastRatio(darkest, midpoint), + GetContrastRatio(midpoint, lightest)); } TEST(ColorUtils, GetColorWithMinimumContrast_ForegroundAlreadyMeetsMinimum) { @@ -236,15 +248,13 @@ } TEST(ColorUtils, GetColorWithMinimumContrast_StopsAtDarkestColor) { - SkColor old_black_color = GetDarkestColor(); - const SkColor darkest_color = SkColorSetRGB(0x44, 0x44, 0x44); - SetDarkestColor(darkest_color); + const SkColor old_darkest_color = SetDarkestColorForTesting(darkest_color); EXPECT_EQ(darkest_color, GetColorWithMinimumContrast(SkColorSetRGB(0x55, 0x55, 0x55), SkColorSetRGB(0xAA, 0xAA, 0xAA))); - SetDarkestColor(old_black_color); + SetDarkestColorForTesting(old_darkest_color); } TEST(ColorUtils, GetBlendValueWithMinimumContrast_ComputesExpectedOpacities) {
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn index 868136f..7757bdf 100644 --- a/ui/views/BUILD.gn +++ b/ui/views/BUILD.gn
@@ -679,6 +679,7 @@ "widget/desktop_aura/desktop_native_widget_aura.cc", "widget/desktop_aura/desktop_screen.cc", "widget/desktop_aura/desktop_screen_position_client.cc", + "widget/desktop_aura/desktop_window_tree_host.cc", "widget/focus_manager_event_handler.cc", "widget/native_widget_aura.cc", "widget/tooltip_manager_aura.cc",
diff --git a/ui/views/mus/desktop_window_tree_host_mus.cc b/ui/views/mus/desktop_window_tree_host_mus.cc index 150ca0d..01813e6 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.cc +++ b/ui/views/mus/desktop_window_tree_host_mus.cc
@@ -385,14 +385,6 @@ .device_scale_factor(); } -void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) { - // Do not use ConvertRectToPixel, enclosing rects cause problems. - const gfx::Rect rect( - gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), GetScaleFactor()), - gfx::ScaleToCeiledSize(bounds_in_dip.size(), GetScaleFactor())); - SetBoundsInPixels(rect, viz::LocalSurfaceIdAllocation()); -} - bool DesktopWindowTreeHostMus::IsWaitingForRestoreToComplete() const { return window_tree_host_window_observer_->is_waiting_for_restore(); } @@ -1015,6 +1007,14 @@ return false; } +void DesktopWindowTreeHostMus::SetBoundsInDIP(const gfx::Rect& bounds_in_dip) { + // Do not use ConvertRectToPixel, enclosing rects cause problems. + const gfx::Rect rect( + gfx::ScaleToFlooredPoint(bounds_in_dip.origin(), GetScaleFactor()), + gfx::ScaleToCeiledSize(bounds_in_dip.size(), GetScaleFactor())); + SetBoundsInPixels(rect, viz::LocalSurfaceIdAllocation()); +} + void DesktopWindowTreeHostMus::OnWindowManagerFrameValuesChanged() { NonClientView* non_client_view = native_widget_delegate_->AsWidget()->non_client_view();
diff --git a/ui/views/mus/desktop_window_tree_host_mus.h b/ui/views/mus/desktop_window_tree_host_mus.h index 6d61f260..4a58e2d 100644 --- a/ui/views/mus/desktop_window_tree_host_mus.h +++ b/ui/views/mus/desktop_window_tree_host_mus.h
@@ -59,8 +59,6 @@ // Helper function to get the scale factor. float GetScaleFactor() const; - void SetBoundsInDIP(const gfx::Rect& bounds_in_dip); - // Returns true if the client area should be set on this. bool ShouldSendClientAreaToServer() const; @@ -149,6 +147,7 @@ bool ShouldUpdateWindowTransparency() const override; bool ShouldUseDesktopNativeCursorManager() const override; bool ShouldCreateVisibilityController() const override; + void SetBoundsInDIP(const gfx::Rect& bounds_in_dip) override; // MusClientObserver: void OnWindowManagerFrameValuesChanged() override;
diff --git a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc index 9959576..d266b9e 100644 --- a/ui/views/mus/desktop_window_tree_host_mus_unittest.cc +++ b/ui/views/mus/desktop_window_tree_host_mus_unittest.cc
@@ -916,4 +916,41 @@ transient_child->RemoveObserver(&observer); } +// DesktopWindowTreeHostMusTest with --force-device-scale-factor=1.25. +class DesktopWindowTreeHostMusTestFractionalDPI + : public DesktopWindowTreeHostMusTest { + public: + DesktopWindowTreeHostMusTestFractionalDPI() = default; + ~DesktopWindowTreeHostMusTestFractionalDPI() override = default; + + // DesktopWindowTreeHostMusTest: + void SetUp() override { + base::CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kForceDeviceScaleFactor, "1.25"); + DesktopWindowTreeHostMusTest::SetUp(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(DesktopWindowTreeHostMusTestFractionalDPI); +}; + +TEST_F(DesktopWindowTreeHostMusTestFractionalDPI, + SetBoundsInDipWithFractionalScale) { + std::unique_ptr<Widget> widget(CreateWidget()); + // These numbers are carefully chosen such that if enclosing rect is used + // the pixel values differ between the two. The WindowServcie assumes ceiling + // is used on the size, which is not impacted by the location. + const gfx::Rect bounds1(408, 48, 339, 296); + const int expected_pixel_height = + gfx::ScaleToCeiledSize(bounds1.size(), 1.25f).height(); + widget->SetBounds(bounds1); + EXPECT_EQ(expected_pixel_height, + widget->GetNativeWindow()->GetHost()->GetBoundsInPixels().height()); + + const gfx::Rect bounds2(gfx::Point(408, 49), bounds1.size()); + widget->SetBounds(bounds2); + EXPECT_EQ(expected_pixel_height, + widget->GetNativeWindow()->GetHost()->GetBoundsInPixels().height()); +} + } // namespace views
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 afd5488c..f7144e6 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -23,7 +23,6 @@ #include "ui/base/hit_test.h" #include "ui/base/ime/input_method.h" #include "ui/compositor/layer.h" -#include "ui/display/screen.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/rect.h" @@ -728,11 +727,7 @@ void DesktopNativeWidgetAura::SetBounds(const gfx::Rect& bounds) { if (!content_window_) return; - aura::Window* root = host_->window(); - display::Screen* screen = display::Screen::GetScreen(); - gfx::Rect bounds_in_pixels = screen->DIPToScreenRectInWindow(root, bounds); - desktop_window_tree_host_->AsWindowTreeHost()->SetBoundsInPixels( - bounds_in_pixels); + desktop_window_tree_host_->SetBoundsInDIP(bounds); } void DesktopNativeWidgetAura::SetBoundsConstrained(const gfx::Rect& bounds) {
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host.cc new file mode 100644 index 0000000..6125dbe --- /dev/null +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host.cc
@@ -0,0 +1,20 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/views/widget/desktop_aura/desktop_window_tree_host.h" + +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" +#include "ui/display/screen.h" + +namespace views { + +void DesktopWindowTreeHost::SetBoundsInDIP(const gfx::Rect& bounds) { + aura::Window* root = AsWindowTreeHost()->window(); + const gfx::Rect bounds_in_pixels = + display::Screen::GetScreen()->DIPToScreenRectInWindow(root, bounds); + AsWindowTreeHost()->SetBoundsInPixels(bounds_in_pixels); +} + +} // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host.h b/ui/views/widget/desktop_aura/desktop_window_tree_host.h index 8a909991..a0ec589 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host.h
@@ -187,6 +187,10 @@ // Returns whether a VisibilityController should be created. virtual bool ShouldCreateVisibilityController() const = 0; + + // Sets the bounds in screen coordinate DIPs (WindowTreeHost generally + // operates in pixels). This function is implemented in terms of Screen. + virtual void SetBoundsInDIP(const gfx::Rect& bounds); }; } // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc index f615231..24017c9 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.cc
@@ -72,14 +72,6 @@ DestroyDispatcher(); } -void DesktopWindowTreeHostPlatform::SetBoundsInDIP( - const gfx::Rect& bounds_in_dip) { - DCHECK_NE(0, device_scale_factor()); - SetBoundsInPixels( - gfx::ConvertRectToPixel(device_scale_factor(), bounds_in_dip), - viz::LocalSurfaceIdAllocation()); -} - void DesktopWindowTreeHostPlatform::Init(const Widget::InitParams& params) { ui::PlatformWindowInitProperties properties = ConvertWidgetInitParamsToInitProperties(params);
diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h index fa10671..039683e7 100644 --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_platform.h
@@ -24,8 +24,6 @@ DesktopNativeWidgetAura* desktop_native_widget_aura); ~DesktopWindowTreeHostPlatform() override; - void SetBoundsInDIP(const gfx::Rect& bounds_in_dip); - // DesktopWindowTreeHost: void Init(const Widget::InitParams& params) override; void OnNativeWidgetCreated(const Widget::InitParams& params) override;
diff --git a/ui/webui/resources/images/error_badge.svg b/ui/webui/resources/images/error_badge.svg new file mode 100644 index 0000000..4367b025 --- /dev/null +++ b/ui/webui/resources/images/error_badge.svg
@@ -0,0 +1,9 @@ +<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <defs> + <path d="M10 2c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm.8 12H9.2v-1.6h1.6V14zm0-3.2H9.2V6h1.6v4.8z" id="a"/> + </defs> + <g fill="none" fill-rule="evenodd"> + <circle fill="#FFF" cx="10" cy="10" r="10"/> + <use fill="#D93025" fill-rule="nonzero" xlink:href="#a"/> + </g> +</svg>
diff --git a/ui/webui/resources/webui_resources.grd b/ui/webui/resources/webui_resources.grd index b22111a..2e2aec3 100644 --- a/ui/webui/resources/webui_resources.grd +++ b/ui/webui/resources/webui_resources.grd
@@ -185,6 +185,9 @@ file="images/disabled_select.png" type="BINDATA" /> <include name="IDR_WEBUI_IMAGES_ERROR" file="images/error.svg" type="BINDATA" compress="gzip" /> + <!-- Similar to IDR_WEBUI_IMAGES_ERROR except that it is white-filled instead of transparent-filled. Useful for badging images where the background may be red. --> + <include name="IDR_WEBUI_IMAGES_ERROR_BADGE" + file="images/error_badge.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_GOOGLE_LOGO" file="images/google_logo.svg" type="BINDATA" compress="gzip" /> <include name="IDR_WEBUI_IMAGES_SELECT"