diff --git a/.gn b/.gn index 78b6f72..e3ff7d4b 100644 --- a/.gn +++ b/.gn
@@ -253,7 +253,6 @@ "//third_party/blink/renderer/modules/canvas:*", # 1 error "//third_party/blink/renderer/modules/font_access:*", # 3 errors "//third_party/blink/renderer/modules/peerconnection:*", # 43 errors - "//third_party/blink/renderer/modules:*", # 321 errors "//third_party/blink/renderer/platform:*", # 10 errors "//third_party/breakpad:*", # 34 errors
diff --git a/DEPS b/DEPS index 0d31b9c..e3f78b84 100644 --- a/DEPS +++ b/DEPS
@@ -195,7 +195,7 @@ # 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': '186866c46179af3afeb93d23889fe7a4386cf090', + 'skia_revision': '081bc32703b7eb62728e6b5478e24e55c8f84463', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -207,7 +207,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': '2879eb5512c2e42998dc4ecb08d338d88cb2928e', + 'angle_revision': '183a454b9d5474abb097da2c527805a9c7379a6c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. @@ -258,7 +258,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': 'e53ee0c93173e3b9452c8693e8e0ad07364fd801', + 'catapult_revision': '534924ed9ee5671b616f716581d21e765555f0a5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -266,7 +266,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling devtools-frontend # and whatever else without interference from each other. - 'devtools_frontend_revision': '75bcb7c214928177d74c6ed20a119ebf6212b5e3', + 'devtools_frontend_revision': '01a6665d9a382f0c77c4d922c9211615e002e021', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libprotobuf-mutator # and whatever else without interference from each other. @@ -302,7 +302,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': '2de7d3af0c0ed8b0fcff7b83b36c5a7424e51e19', + 'spv_tools_revision': '726af6f78f80988271c8b558ae9cc84fa5a65016', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -947,7 +947,7 @@ Var('chromium_git') + '/codecs/libgav1.git' + '@' + 'a9449e612bc251b4271bbe1e3a0d12e9809bf74c', 'src/third_party/glslang/src': - Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '6a6e311d81ddfa6debf5659f05c311e3b57b5f77', + Var('chromium_git') + '/external/github.com/KhronosGroup/glslang.git' + '@' + '759ae5aec02bd6fe5f58a9c7cd6c98cc1968c7b5', 'src/third_party/google_toolbox_for_mac/src': { 'url': Var('chromium_git') + '/external/github.com/google/google-toolbox-for-mac.git' + '@' + Var('google_toolbox_for_mac_revision'), @@ -1471,7 +1471,7 @@ }, 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + '5c8aa5cd05ae56ac783145a04ed21c5ebd2dfc4d', + Var('webrtc_git') + '/src.git' + '@' + '71d7c8e3cdd61b69d09fc392b93cc8c461168f0d', 'src/third_party/libgifcodec': Var('skia_git') + '/libgifcodec' + '@'+ Var('libgifcodec_revision'), @@ -1562,7 +1562,7 @@ 'packages': [ { 'package': 'chromeos_internal/apps/media_app/app', - 'version': 'TYOLo4rtVMC49lR5yvwouWlMavyGxEBRTimkq5QQimEC', + 'version': 'MEjLKGkVlDNdHj0W1rgJY5UBkUoBb16icAog6f-mvaEC', }, ], 'condition': 'checkout_chromeos and checkout_src_internal',
diff --git a/ash/resources/vector_icons/battery.icon b/ash/resources/vector_icons/battery.icon index 8afc456..924942b 100644 --- a/ash/resources/vector_icons/battery.icon +++ b/ash/resources/vector_icons/battery.icon
@@ -3,23 +3,23 @@ // found in the LICENSE file. CANVAS_DIMENSIONS, 20, -MOVE_TO, 13, 4, +MOVE_TO, 13, 4.5f, H_LINE_TO, 12, -V_LINE_TO, 2.5f, +V_LINE_TO, 3, H_LINE_TO, 8, -V_LINE_TO, 4, +V_LINE_TO, 4.5f, H_LINE_TO, 7, -CUBIC_TO, 6.5f, 4, 6, 4.5f, 6, 5, +CUBIC_TO, 6.5f, 4.5f, 6, 5, 6, 5.5f, V_LINE_TO, 16, CUBIC_TO, 6, 16.5f, 6.5f, 17, 7, 17, H_LINE_TO, 13, CUBIC_TO, 13.5f, 17, 14, 16.5f, 14, 16, -V_LINE_TO, 5, -CUBIC_TO, 14, 4.5f, 13.5f, 4, 13, 4, +V_LINE_TO, 5.5f, +CUBIC_TO, 14, 5, 13.5f, 4.5f, 13, 4.5f, CLOSE, -MOVE_TO, 12.5f, 5.5f, +MOVE_TO, 12.5f, 6, H_LINE_TO, 7.5f, V_LINE_TO, 15.5f, H_LINE_TO, 12.5f, -V_LINE_TO, 5.5f, +V_LINE_TO, 6, CLOSE \ No newline at end of file
diff --git a/ash/system/network/network_list_view.cc b/ash/system/network/network_list_view.cc index 6b54ac0e..fb059b14 100644 --- a/ash/system/network/network_list_view.cc +++ b/ash/system/network/network_list_view.cc
@@ -60,7 +60,7 @@ namespace tray { namespace { -const int kMobileNetworkBatteryIconSize = 14; +const int kMobileNetworkBatteryIconSize = 18; const int kPowerStatusPaddingRight = 10; bool IsSecondaryUser() {
diff --git a/ash/system/power/power_status.cc b/ash/system/power/power_status.cc index cba29ad..89bad6ae 100644 --- a/ash/system/power/power_status.cc +++ b/ash/system/power/power_status.cc
@@ -80,7 +80,7 @@ // case, still draw 1dip of charge. SkPath path; - gfx::RectF fill_rect = gfx::RectF(8, 6, 6, 12); + gfx::RectF fill_rect = gfx::RectF(8, 6, 6, 11); fill_rect.Scale(const_scale); path.addRect(gfx::RectToSkRect(gfx::ToEnclosingRect(fill_rect))); cc::PaintFlags flags;
diff --git a/ash/system/power/power_status_unittest.cc b/ash/system/power/power_status_unittest.cc index 1febd58..db9e8070 100644 --- a/ash/system/power/power_status_unittest.cc +++ b/ash/system/power/power_status_unittest.cc
@@ -204,17 +204,17 @@ EXPECT_EQ(0, power_status_->GetBatteryImageInfo().charge_percent); gfx::Image empty_image = get_battery_image(); - // 14% and 15% look different. - prop.set_battery_percent(14.0); + // 10% and 20% look different. + prop.set_battery_percent(10.0); power_status_->SetProtoForTesting(prop); - EXPECT_EQ(14.0, power_status_->GetBatteryImageInfo().charge_percent); - gfx::Image image_14 = get_battery_image(); - EXPECT_FALSE(gfx::test::AreImagesEqual(empty_image, image_14)); - prop.set_battery_percent(15.0); + EXPECT_EQ(10.0, power_status_->GetBatteryImageInfo().charge_percent); + gfx::Image image_10 = get_battery_image(); + EXPECT_FALSE(gfx::test::AreImagesEqual(empty_image, image_10)); + prop.set_battery_percent(20.0); power_status_->SetProtoForTesting(prop); - EXPECT_EQ(15.0, power_status_->GetBatteryImageInfo().charge_percent); - gfx::Image image_15 = get_battery_image(); - EXPECT_FALSE(gfx::test::AreImagesEqual(image_14, image_15)); + EXPECT_EQ(20.0, power_status_->GetBatteryImageInfo().charge_percent); + gfx::Image image_20 = get_battery_image(); + EXPECT_FALSE(gfx::test::AreImagesEqual(image_10, image_20)); // 99% and 100% look different. prop.set_battery_percent(99.0);
diff --git a/ash/system/power/tray_power.cc b/ash/system/power/tray_power.cc index 1a33af1..d687f38 100644 --- a/ash/system/power/tray_power.cc +++ b/ash/system/power/tray_power.cc
@@ -33,6 +33,7 @@ #include "ui/message_center/message_center.h" #include "ui/message_center/public/cpp/notification.h" #include "ui/message_center/public/cpp/notification_delegate.h" +#include "ui/views/border.h" #include "ui/views/controls/image_view.h" #include "ui/views/view.h" @@ -44,6 +45,8 @@ namespace tray { PowerTrayView::PowerTrayView(Shelf* shelf) : TrayItemView(shelf) { + SetBorder( + views::CreateEmptyBorder(0, 0, kUnifiedTrayBatteryBottomPadding, 0)); CreateImageView(); UpdateImage(); UpdateStatus();
diff --git a/ash/system/tray/tray_constants.h b/ash/system/tray/tray_constants.h index 925838e3..045fdcd 100644 --- a/ash/system/tray/tray_constants.h +++ b/ash/system/tray/tray_constants.h
@@ -129,6 +129,7 @@ constexpr int kUnifiedTrayTimeLeftPadding = 1; constexpr int kUnifiedTraySpacingBetweenIcons = 6; constexpr int kUnifiedTrayBatteryWidth = 12; +constexpr int kUnifiedTrayBatteryBottomPadding = 1; constexpr int kUnifiedTrayCornerRadius = 16; constexpr int kUnifiedTrayContentPadding = 12; constexpr int kUnifiedTopShortcutSpacing = 16;
diff --git a/base/files/file.h b/base/files/file.h index 8931b27..2743d1f 100644 --- a/base/files/file.h +++ b/base/files/file.h
@@ -299,7 +299,7 @@ // * Within a process, locking the same file (by the same or new handle) // will succeed. The new lock replaces the old lock. // * Closing any descriptor on a given file releases the lock. - Error Lock(LockMode mode = LockMode::kExclusive); + Error Lock(LockMode mode); // Unlock a file previously locked. Error Unlock();
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 2efed61..ca7de55 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -0.20200912.1.1 +0.20200914.0.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index cf03e74..ca7de55 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -0.20200912.0.1 +0.20200914.0.1
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 04e6025..896b4d1 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -2438,12 +2438,7 @@ if (settings_.force_preferred_interval_for_video || enable_frame_rate_throttling_) { - // For now cap the interval assuming a 24fps video, which is likely the - // lowest frame rate we'll see for a video that would also be acceptable to - // the page. - double interval_in_seconds = 1.0 / 24.0; - metadata.preferred_frame_interval = - base::TimeDelta::FromSecondsD(interval_in_seconds); + metadata.preferred_frame_interval = viz::BeginFrameArgs::MaxInterval(); } else { metadata.preferred_frame_interval = frame_rate_estimator_.GetPreferredInterval();
diff --git a/chrome/VERSION b/chrome/VERSION index e261457d..77fb3c0 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=87 MINOR=0 -BUILD=4263 +BUILD=4264 PATCH=0
diff --git a/chrome/android/chrome_java_resources.gni b/chrome/android/chrome_java_resources.gni index 1e3019c..55ccab9f 100644 --- a/chrome/android/chrome_java_resources.gni +++ b/chrome/android/chrome_java_resources.gni
@@ -904,7 +904,6 @@ "java/res/layout/new_tab_page_feed_v2_expandable_header.xml", "java/res/layout/new_tab_page_incognito.xml", "java/res/layout/new_tab_page_layout.xml", - "java/res/layout/new_tab_page_offline_card.xml", "java/res/layout/new_tab_page_snippets_expandable_header.xml", "java/res/layout/new_tab_page_snippets_expandable_header_with_menu.xml", "java/res/layout/new_tab_page_tile_grid_placeholder.xml",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index c1fe688..e7fe71f 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -1002,7 +1002,6 @@ "java/src/org/chromium/chrome/browser/ntp/TitleUtil.java", "java/src/org/chromium/chrome/browser/ntp/cards/CardsVariationParameters.java", "java/src/org/chromium/chrome/browser/ntp/cards/ChildNode.java", - "java/src/org/chromium/chrome/browser/ntp/cards/ExploreOfflineCard.java", "java/src/org/chromium/chrome/browser/ntp/cards/InnerNode.java", "java/src/org/chromium/chrome/browser/ntp/cards/ItemViewType.java", "java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageViewHolder.java",
diff --git a/chrome/android/java/res/layout/new_tab_page_layout.xml b/chrome/android/java/res/layout/new_tab_page_layout.xml index 0ec624f2..ba75962 100644 --- a/chrome/android/java/res/layout/new_tab_page_layout.xml +++ b/chrome/android/java/res/layout/new_tab_page_layout.xml
@@ -51,15 +51,6 @@ android:layout_marginTop="16dp" android:visibility="gone"/> - <!-- Explore offline card --> - <ViewStub - android:id="@+id/explore_offline_card_stub" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="16dp" - android:layout="@layout/new_tab_page_offline_card" - android:inflatedId="@+id/explore_offline_card" /> - <!-- Middle spacer --> <View android:id="@+id/ntp_middle_spacer"
diff --git a/chrome/android/java/res/layout/new_tab_page_offline_card.xml b/chrome/android/java/res/layout/new_tab_page_offline_card.xml deleted file mode 100644 index 7cc64fc..0000000 --- a/chrome/android/java/res/layout/new_tab_page_offline_card.xml +++ /dev/null
@@ -1,57 +0,0 @@ -<?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. --> - -<RelativeLayout - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto" - android:id="@+id/explore_offline_card" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:background="@drawable/hairline_border_card_background" - android:paddingTop="@dimen/card_padding" - android:paddingStart="@dimen/card_padding" - android:paddingEnd="@dimen/card_padding" - android:paddingBottom="10dp"> - - <org.chromium.ui.widget.ChromeImageView - android:id="@+id/icon" - android:layout_width="24dp" - android:layout_height="24dp" - android:importantForAccessibility="no" - android:tint="@color/modern_blue_600" - app:srcCompat="@drawable/ic_cloud_offline_24dp" /> - - <TextView - android:id="@+id/title" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_toEndOf="@id/icon" - android:layout_marginStart="16dp" - android:text="@string/explore_offline_card_title" - android:focusable="true" - android:focusableInTouchMode="true" - android:textAppearance="@style/TextAppearance.TextLarge.Primary" /> - - <TextView - android:id="@+id/description" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@id/title" - android:layout_alignStart="@id/title" - android:layout_marginTop="6dp" - android:text="@string/explore_offline_card_description" - android:focusable="true" - android:focusableInTouchMode="true" - android:textAppearance="@style/TextAppearance.TextMedium.Secondary" /> - - <org.chromium.components.browser_ui.widget.DualControlLayout - android:id="@+id/button_bar" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_below="@id/description" - app:primaryButtonText="@string/explore_offline_card_explore" - app:secondaryButtonText="@string/no_thanks" - app:buttonAlignment="end" /> -</RelativeLayout>
diff --git a/chrome/android/java/res/menu/main_menu_regroup.xml b/chrome/android/java/res/menu/main_menu_regroup.xml index d3c76065..faa3fd2d 100644 --- a/chrome/android/java/res/menu/main_menu_regroup.xml +++ b/chrome/android/java/res/menu/main_menu_regroup.xml
@@ -88,9 +88,6 @@ android:title="@null" /> </menu> </item> - <item android:id="@+id/paint_preview_show_id" - android:title="@string/menu_paint_preview_show" - android:icon="@drawable/ic_photo_camera" /> <item android:id="@+id/find_in_page_id" android:title="@string/menu_find_in_page" android:icon="@drawable/ic_find_in_page" /> @@ -114,6 +111,9 @@ android:checkable="true" /> </menu> </item> + <item android:id="@+id/paint_preview_show_id" + android:title="@string/menu_paint_preview_show" + android:icon="@drawable/ic_photo_camera" /> <item android:id="@+id/divider_line_id" android:title="@null" /> <item android:id="@+id/reader_mode_prefs_id"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfigHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfigHelper.java index 751555bc..80d434c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfigHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/DownloadManagerUiConfigHelper.java
@@ -15,7 +15,6 @@ return new DownloadManagerUiConfig.Builder() .setUseNewDownloadPath(ChromeFeatureList.isEnabled( ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER)) - .setSupportsGrouping(ChromeFeatureList.isEnabled( - ChromeFeatureList.CONTENT_INDEXING_DOWNLOAD_HOME)); + .setSupportsGrouping(true); } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java index 0ee1280..03d79577 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/PictureInPictureController.java
@@ -200,17 +200,17 @@ // We don't want InfoBars displaying while in PiP, they cover too much content. InfoBarContainer.get(activity.getActivityTab()).setHidden(true); + // Setup observers to dismiss the Activity on events that should end PiP. + final Tab activityTab = activity.getActivityTab(); + mOnLeavePipCallbacks.add(new Callback<ChromeActivity>() { @Override public void onResult(ChromeActivity activity2) { webContents.setHasPersistentVideo(false); - InfoBarContainer.get(activity.getActivityTab()).setHidden(false); + InfoBarContainer.get(activityTab).setHidden(false); } }); - // Setup observers to dismiss the Activity on events that should end PiP. - final Tab activityTab = activity.getActivityTab(); - final TabObserver tabObserver = new DismissActivityOnTabEventObserver(activity); final TabModelSelectorObserver tabModelSelectorObserver = new DismissActivityOnTabModelSelectorEventObserver(activity);
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 1569fda0..80684745 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
@@ -29,14 +29,11 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider; import org.chromium.chrome.browser.cryptids.ProbabilisticCryptidRenderer; -import org.chromium.chrome.browser.download.DownloadOpenSource; -import org.chromium.chrome.browser.download.DownloadUtils; import org.chromium.chrome.browser.explore_sites.ExperimentalExploreSitesSection; import org.chromium.chrome.browser.explore_sites.ExploreSitesBridge; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.native_page.ContextMenuManager; import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener; -import org.chromium.chrome.browser.ntp.cards.ExploreOfflineCard; import org.chromium.chrome.browser.ntp.search.SearchBoxCoordinator; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils; @@ -93,7 +90,6 @@ private LogoDelegateImpl mLogoDelegate; private TileGroup mTileGroup; private UiConfig mUiConfig; - private Supplier<Tab> mTabProvider; private CallbackController mCallbackController = new CallbackController(); /** @@ -128,7 +124,6 @@ private int mSearchBoxBoundsVerticalInset; private ScrollDelegate mScrollDelegate; - private ExploreOfflineCard mExploreOfflineCard; private NewTabPageUma mNewTabPageUma; @@ -177,7 +172,6 @@ super.onFinishInflate(); mMiddleSpacer = findViewById(R.id.ntp_middle_spacer); mSearchProviderLogoView = findViewById(R.id.search_provider_logo); - mExploreOfflineCard = new ExploreOfflineCard(this, openDownloadHomeCallback()); insertSiteSectionView(); int variation = ExploreSitesBridge.getVariation(); @@ -223,7 +217,6 @@ mManager = manager; mActivity = activity; mUiConfig = uiConfig; - mTabProvider = tabProvider; mNewTabPageUma = uma; Profile profile = Profile.getLastUsedRegularProfile(); @@ -875,7 +868,6 @@ mCallbackController = null; } - if (mExploreOfflineCard != null) mExploreOfflineCard.destroy(); VrModuleProvider.unregisterVrModeObserver(this); if (mSearchProviderLogoView != null) { @@ -912,13 +904,6 @@ } } - private Runnable openDownloadHomeCallback() { - return () -> { - DownloadUtils.showDownloadManager(mActivity, mTabProvider.get(), - DownloadOpenSource.NEW_TAB_PAGE, true /*showPrefetchedContent*/); - }; - } - /** * Convenience method to call measure() on the given View with MeasureSpecs converted from the * given dimensions (in pixels) with MeasureSpec.EXACTLY.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ExploreOfflineCard.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ExploreOfflineCard.java deleted file mode 100644 index d8889d6..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/ExploreOfflineCard.java +++ /dev/null
@@ -1,113 +0,0 @@ -// Copyright 2019 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -package org.chromium.chrome.browser.ntp.cards; - -import android.view.View; -import android.view.ViewStub; -import android.widget.Button; - -import androidx.annotation.IntDef; - -import org.chromium.base.metrics.RecordHistogram; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.download.ExploreOfflineStatusProvider; -import org.chromium.chrome.browser.flags.ChromeFeatureList; -import org.chromium.net.NetworkChangeNotifier; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Shows a card prompting the user to view offline content when they are offline. This class is - * responsible for inflating the card layout and displaying the card based on network connectivity. - */ -public class ExploreOfflineCard { - // Please treat this list as append only and keep it in sync with - // NewTabPage.ExploreOffline.Action in enums.xml. - @IntDef({Action.SHOWN, Action.CONFIRM, Action.CANCEL}) - @Retention(RetentionPolicy.SOURCE) - public @interface Action { - int SHOWN = 0; - int CONFIRM = 1; - int CANCEL = 2; - int NUM_ENTRIES = 3; - } - - private static boolean sCardDismissed; - private final View mRootView; - private final Runnable mOpenDownloadHomeCallback; - private NetworkChangeNotifier.ConnectionTypeObserver mConnectionTypeObserver; - - /** - * Constructor. - * @param rootView The parent view where this card should be inflated. - * @param openDownloadHomeCallback A callback to open download home. - */ - public ExploreOfflineCard(View rootView, Runnable openDownloadHomeCallback) { - mRootView = rootView; - mOpenDownloadHomeCallback = openDownloadHomeCallback; - - if (!isFeatureEnabled()) return; - setCardViewVisibility(); - mConnectionTypeObserver = connectionType -> { - setCardViewVisibility(); - }; - - NetworkChangeNotifier.addConnectionTypeObserver(mConnectionTypeObserver); - } - - /** Called during destruction of the view. */ - public void destroy() { - NetworkChangeNotifier.removeConnectionTypeObserver(mConnectionTypeObserver); - } - - private void setCardViewVisibility() { - boolean isVisible = !sCardDismissed && shouldShowExploreOfflineMessage(); - View cardView = mRootView.findViewById(R.id.explore_offline_card); - - if (cardView == null) { - if (!isVisible) return; - cardView = inflateCardLayout(); - } - cardView.setVisibility(isVisible ? View.VISIBLE : View.GONE); - } - - private View inflateCardLayout() { - View cardView = - ((ViewStub) mRootView.findViewById(R.id.explore_offline_card_stub)).inflate(); - Button confirmButton = cardView.findViewById(R.id.button_primary); - Button cancelButton = cardView.findViewById(R.id.button_secondary); - - confirmButton.setOnClickListener(v -> { - sCardDismissed = true; - setCardViewVisibility(); - mOpenDownloadHomeCallback.run(); - recordStats(Action.CONFIRM); - }); - cancelButton.setOnClickListener(v -> { - sCardDismissed = true; - setCardViewVisibility(); - recordStats(Action.CANCEL); - }); - - recordStats(Action.SHOWN); - return cardView; - } - - private void recordStats(@Action int action) { - RecordHistogram.recordEnumeratedHistogram( - "NewTabPage.ExploreOffline.Action", action, Action.NUM_ENTRIES); - } - - private static boolean shouldShowExploreOfflineMessage() { - return isFeatureEnabled() && NetworkChangeNotifier.isInitialized() - && !NetworkChangeNotifier.isOnline() - && ExploreOfflineStatusProvider.getInstance().isPrefetchContentAvailable(); - } - - private static boolean isFeatureEnabled() { - return ChromeFeatureList.isEnabled(ChromeFeatureList.CONTENT_INDEXING_NTP); - } -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java index 8d7efad5..4ff47c2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/home/DownloadActivityV2Test.java
@@ -123,7 +123,6 @@ features.put(ChromeFeatureList.OFFLINE_PAGES_PREFETCHING, true); features.put(ChromeFeatureList.OVERSCROLL_HISTORY_NAVIGATION, false); features.put(ChromeFeatureList.DOWNLOAD_OFFLINE_CONTENT_PROVIDER, false); - features.put(ChromeFeatureList.CONTENT_INDEXING_DOWNLOAD_HOME, false); ChromeFeatureList.setTestFeatures(features); mStubbedOfflineContentProvider = new StubbedOfflineContentProvider() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java index 3ec538d..d2d882a90 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/translate/TranslateCompactInfoBarTest.java
@@ -5,6 +5,7 @@ package org.chromium.chrome.browser.translate; import android.content.pm.ActivityInfo; +import android.os.Build.VERSION_CODES; import android.support.test.InstrumentationRegistry; import androidx.test.filters.MediumTest; @@ -17,6 +18,7 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.base.test.util.DisableIf; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; @@ -201,7 +203,11 @@ @MediumTest @Feature({"Browser", "Main"}) @Restriction(ChromeRestriction.RESTRICTION_TYPE_GOOGLE_PLAY_SERVICES) - public void testManualInitiationWithBarOpen() throws TimeoutException { + @DisableIf. + Build(sdk_is_greater_than = VERSION_CODES.LOLLIPOP_MR1, sdk_is_less_than = VERSION_CODES.N, + message = "Consistently failing on Marshmallow https://crbug.com/1127786") + public void + testManualInitiationWithBarOpen() throws TimeoutException { mActivityTestRule.loadUrl(mTestServer.getURL(TRANSLATE_PAGE)); mListener.addInfoBarAnimationFinished("InfoBar not opened.");
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 687e771..96cac6f 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -6098,7 +6098,7 @@ <message name="IDS_PASSWORD_MANAGER_SAVE_BUTTON" desc="Mobile: Button text for the 'Save Password' infobar's 'Remember password' option"> Save </message> - <message name="IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON" desc="Mobile: Button text for the 'Save Password' infobar's 'Never remember for this site' option"> + <message name="IDS_PASSWORD_MANAGER_BLOCKLIST_BUTTON" desc="Mobile: Button text for the 'Save Password' infobar's 'Never remember for this site' option"> Never </message> <message name="IDS_PASSWORD_MANAGER_UPDATE_BUTTON" desc="Label for the 'update' button in the Update Password infobar. This infobar asks if the user wishes to update the saved password for a site to a new password the user has just entered; the button applies the suggested update."> @@ -7573,7 +7573,7 @@ Thumbnail removed. </message> <message name="IDS_NEW_TAB_REMOVE_THUMBNAIL_TOOLTIP" - desc="Tooltip text for the button that removes/blacklists the thumbnail. Once removed the thumbnail will not show up on the new tab page again."> + desc="Tooltip text for the button that removes/denylists the thumbnail. Once removed the thumbnail will not show up on the new tab page again."> Don't show on this page </message> <message name="IDS_NEW_TAB_PAGE_SWITCHER_CHANGE_TITLE" @@ -10070,7 +10070,7 @@ </message> <!-- Ad Blocking UI strings. --> - <message name="IDS_ALWAYS_ALLOW_ADS" desc="Explanation associated with a toggle to allow ads after ads have been blocked on the page. To be used on pages where the ad blocking UI is governed by a persistent permissions-based whitelist."> + <message name="IDS_ALWAYS_ALLOW_ADS" desc="Explanation associated with a toggle to allow ads after ads have been blocked on the page. To be used on pages where the ad blocking UI is governed by a persistent permissions-based allowlist."> Always allow ads on this site </message> <message name="IDS_BLOCKED_ADS_INFOBAR_MESSAGE" desc="The mini infobar message shown to users on Android when Chrome has blocked ads on the site because the site tends to show intrusive ads. Will be presented as a sentence, next to a Details link to expand the infobar.">
diff --git a/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_BLOCKLIST_BUTTON.png.sha1 b/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_BLOCKLIST_BUTTON.png.sha1 new file mode 100644 index 0000000..188313d --- /dev/null +++ b/chrome/app/generated_resources_grd/IDS_PASSWORD_MANAGER_BLOCKLIST_BUTTON.png.sha1
@@ -0,0 +1 @@ +732097e99423da95fef57651781a3bdc279d55f1 \ No newline at end of file
diff --git a/chrome/app/os_settings_search_tag_strings.grdp b/chrome/app/os_settings_search_tag_strings.grdp index c8a0718c..0583987 100644 --- a/chrome/app/os_settings_search_tag_strings.grdp +++ b/chrome/app/os_settings_search_tag_strings.grdp
@@ -889,6 +889,9 @@ <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_SPELL_CHECK" translateable="false" desc="Text for search result item which, when clicked, navigates the user to input settings, with all the options for spell check settings"> Spell check </message> + <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_EDIT_DICTIONARY" translateable="false" desc="Text for search result item which, when clicked, navigates the user to edit dictionary page."> + Customize spell check + </message> <message name="IDS_OS_SETTINGS_TAG_LANGUAGES_INPUT_METHODS" desc="Text for search result item which, when clicked, navigates the user to input settings, with the option to enable/disable input in supported languages."> Manage input methods </message>
diff --git a/chrome/app/os_settings_strings.grdp b/chrome/app/os_settings_strings.grdp index 7902de8..75c0d501 100644 --- a/chrome/app/os_settings_strings.grdp +++ b/chrome/app/os_settings_strings.grdp
@@ -277,6 +277,9 @@ <message name="IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PREFERENCE_DESCRIPTION" translateable="false" desc="The description of the section in the language settings page where users can add languages they read to an ordered list. The web content languages will be served in the order of the list."> Add and order languages you read. Apps and websites will be displayed in the most preferred language available. <ph name="BEGIN_LINK_LEARN_MORE"><a target="_blank" href="$1"></ph>Learn more<ph name="END_LINK_LEARN_MORE"></a></ph> </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_TRANSLATE_TARGET_LABEL" translateable="false" desc="The label of the toggle that enables the prompt to translate a page to users."> + The language is used when translating pages + </message> <message name="IDS_OS_SETTINGS_LANGUAGES_OFFER_TRANSLATION_LABEL" translateable="false" desc="The label of the toggle that enables the prompt to translate a page to users."> Translation suggestion </message> @@ -319,6 +322,24 @@ <message name="IDS_OS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_LABEL" translateable="false" desc="Label for the section for users to add custom words for no spell check."> Customize spell check </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_DESCRIPTION" translateable="false" desc="Description for the section for users to add custom words for no spell check."> + Add words you want spell check to skip + </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_BUTTON_LABEL" translateable="false" desc="Description for the button for users to add custom words for no spell check."> + Add word + </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_DUPLICATE_ERROR" translateable="false" desc="Error message displayed to the user when the word is duplicated in the text input used to add a new word to the custom spell check dictionary."> + Word already added + </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_LENGTH_ERROR" translateable="false" desc="Error message displayed to the user when the word is too long in the text input used to add a new word to the custom spell check dictionary."> + Use 99 letters or fewer for new words + </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_DELETE_DICTIONARY_WORD_TOOLTIP" translateable="false" desc="Description for the tooltip that appear when users hover over the icon to delete a custom words."> + Delete word + </message> + <message name="IDS_OS_SETTINGS_LANGUAGES_NO_DICTIONARY_WORDS_LABEL" translateable="false" desc="Description for the label that appear when there are no custom words in the dictionary."> + Saved custom words will appear here + </message> <message name="IDS_OS_SETTINGS_LANGUAGES_LIST_TITLE" desc="Title for the list of the user's preferred written languages."> Languages </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index bcda2d5..b30dfa9 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -196,6 +196,7 @@ #include "components/external_intents/android/external_intents_feature_list.h" #else // OS_ANDROID #include "chrome/browser/media/router/media_router_feature.h" +#include "chrome/browser/web_applications/components/external_app_install_features.h" #endif // OS_ANDROID #if defined(OS_CHROMEOS) @@ -3079,6 +3080,18 @@ flag_descriptions::kAllowAllSitesToInitiateMirroringDescription, kOsDesktop, FEATURE_VALUE_TYPE(media_router::kAllowAllSitesToInitiateMirroring)}, + {"enable-migrate-default-chrome-app-to-web-apps-gsuite", + flag_descriptions::kEnableMigrateDefaultChromeAppToWebAppsGSuiteName, + flag_descriptions:: + kEnableMigrateDefaultChromeAppToWebAppsGSuiteDescription, + kOsDesktop, + FEATURE_VALUE_TYPE(web_app::kMigrateDefaultChromeAppToWebAppsGSuite)}, + {"enable-migrate-default-chrome-app-to-web-apps-non-gsuite", + flag_descriptions::kEnableMigrateDefaultChromeAppToWebAppsNonGSuiteName, + flag_descriptions:: + kEnableMigrateDefaultChromeAppToWebAppsNonGSuiteDescription, + kOsDesktop, + FEATURE_VALUE_TYPE(web_app::kMigrateDefaultChromeAppToWebAppsNonGSuite)}, #endif // !OS_ANDROID #if defined(OS_ANDROID) {"autofill-keyboard-accessory-view", @@ -3178,13 +3191,6 @@ flag_descriptions::kOfflineIndicatorAlwaysHttpProbeDescription, kOsAndroid, FEATURE_VALUE_TYPE( offline_pages::kOfflineIndicatorAlwaysHttpProbeFeature)}, - {"content-indexing-download-home", - flag_descriptions::kContentIndexingDownloadHomeName, - flag_descriptions::kContentIndexingDownloadHomeDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kContentIndexingDownloadHome)}, - {"content-indexing-ntp", flag_descriptions::kContentIndexingNTPName, - flag_descriptions::kContentIndexingNTPDescription, kOsAndroid, - FEATURE_VALUE_TYPE(chrome::android::kContentIndexingNTP)}, {"offline-indicator-v2", flag_descriptions::kOfflineIndicatorV2Name, flag_descriptions::kOfflineIndicatorV2Description, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kOfflineIndicatorV2)},
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc index b072336..3796d84 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -536,7 +536,7 @@ dbus_services_.reset(new internal::DBusServices(parameters())); // Need to be done after LoginState has been initialized in DBusServices(). - memory_kills_monitor_ = memory::MemoryKillsMonitor::Initialize(); + memory::MemoryKillsMonitor::Initialize(); ChromeBrowserMainPartsLinux::PostMainMessageLoopStart(); }
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.h b/chrome/browser/chromeos/chrome_browser_main_chromeos.h index fddca4aa..7db0366 100644 --- a/chrome/browser/chromeos/chrome_browser_main_chromeos.h +++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.h
@@ -155,8 +155,6 @@ std::unique_ptr<ArcKioskAppManager> arc_kiosk_app_manager_; std::unique_ptr<WebKioskAppManager> web_kiosk_app_manager_; - std::unique_ptr<::memory::MemoryKillsMonitor::Handle> memory_kills_monitor_; - std::unique_ptr<ChromeKeyboardControllerClient> chrome_keyboard_controller_client_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.cc b/chrome/browser/chromeos/extensions/file_manager/event_router.cc index a4a8fc5..9f00749 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.cc
@@ -52,6 +52,7 @@ #include "extensions/browser/event_router.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" #include "storage/browser/file_system/external_mount_points.h" #include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_util.h" @@ -449,6 +450,8 @@ content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this); + extensions::ExtensionRegistry::Get(profile_)->RemoveObserver(this); + DriveIntegrationService* const integration_service = DriveIntegrationServiceFactory::FindForProfile(profile_); if (integration_service) { @@ -504,6 +507,8 @@ content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this); + extensions::ExtensionRegistry::Get(profile_)->AddObserver(this); + pref_change_registrar_->Init(profile_->GetPrefs()); base::Closure callback = base::Bind(&EventRouter::OnFileManagerPrefsChanged, @@ -651,14 +656,19 @@ } void EventRouter::OnConnectionChanged(network::mojom::ConnectionType type) { - DCHECK(profile_); - DCHECK(extensions::EventRouter::Get(profile_)); + NotifyDriveConnectionStatusChanged(); +} - BroadcastEvent( - profile_, extensions::events:: - FILE_MANAGER_PRIVATE_ON_DRIVE_CONNECTION_STATUS_CHANGED, - file_manager_private::OnDriveConnectionStatusChanged::kEventName, - file_manager_private::OnDriveConnectionStatusChanged::Create()); +void EventRouter::OnExtensionLoaded(content::BrowserContext* browser_context, + const extensions::Extension* extension) { + NotifyDriveConnectionStatusChanged(); +} + +void EventRouter::OnExtensionUnloaded( + content::BrowserContext* browser_context, + const extensions::Extension* extension, + extensions::UnloadedExtensionReason reason) { + NotifyDriveConnectionStatusChanged(); } void EventRouter::TimezoneChanged(const icu::TimeZone& timezone) { @@ -917,6 +927,18 @@ } } +void EventRouter::NotifyDriveConnectionStatusChanged() { + DCHECK(profile_); + DCHECK(extensions::EventRouter::Get(profile_)); + + BroadcastEvent( + profile_, + extensions::events:: + FILE_MANAGER_PRIVATE_ON_DRIVE_CONNECTION_STATUS_CHANGED, + file_manager_private::OnDriveConnectionStatusChanged::kEventName, + file_manager_private::OnDriveConnectionStatusChanged::Create()); +} + base::WeakPtr<EventRouter> EventRouter::GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h index 109996b..6cffac1 100644 --- a/chrome/browser/chromeos/extensions/file_manager/event_router.h +++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -30,6 +30,7 @@ #include "components/arc/arc_service_manager.h" #include "components/arc/intent_helper/arc_intent_helper_observer.h" #include "components/keyed_service/core/keyed_service.h" +#include "extensions/browser/extension_registry_observer.h" #include "services/network/public/cpp/network_connection_tracker.h" #include "storage/browser/file_system/file_system_operation.h" @@ -45,6 +46,7 @@ class EventRouter : public KeyedService, public network::NetworkConnectionTracker::NetworkConnectionObserver, + public extensions::ExtensionRegistryObserver, public chromeos::system::TimezoneSettings::Observer, public VolumeManagerObserver, public arc::ArcIntentHelperObserver, @@ -109,6 +111,13 @@ // network::NetworkConnectionTracker::NetworkConnectionObserver overrides. void OnConnectionChanged(network::mojom::ConnectionType type) override; + // extensions::ExtensionRegistryObserver overrides + void OnExtensionLoaded(content::BrowserContext* browser_context, + const extensions::Extension* extension) override; + void OnExtensionUnloaded(content::BrowserContext* browser_context, + const extensions::Extension* extension, + extensions::UnloadedExtensionReason reason) override; + // chromeos::system::TimezoneSettings::Observer overrides. void TimezoneChanged(const icu::TimeZone& timezone) override; @@ -200,6 +209,8 @@ extensions::api::file_manager_private::CrostiniEventType pref_true, extensions::api::file_manager_private::CrostiniEventType pref_false); + void NotifyDriveConnectionStatusChanged(); + base::Time last_copy_progress_event_; std::map<base::FilePath, std::unique_ptr<FileWatcher>> file_watchers_;
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc index b00ae2f..76b4e62f 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -12,6 +12,7 @@ #include "base/base64.h" #include "base/bind.h" #include "base/command_line.h" +#include "base/feature_list.h" #include "base/i18n/string_search.h" #include "base/memory/ptr_util.h" #include "base/metrics/histogram_functions.h" @@ -25,6 +26,7 @@ #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root.h" #include "chrome/browser/chromeos/arc/fileapi/arc_documents_provider_root_map.h" #include "chrome/browser/chromeos/drive/drive_integration_service.h" +#include "chrome/browser/chromeos/drive/drivefs_native_message_host.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/extensions/file_manager/private_api_util.h" #include "chrome/browser/chromeos/file_manager/file_tasks.h" @@ -41,7 +43,9 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/common/extensions/api/file_manager_private_internal.h" +#include "chrome/common/extensions/extension_constants.h" #include "chromeos/components/drivefs/drivefs_util.h" +#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_switches.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_state_handler.h" @@ -53,6 +57,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/storage_partition.h" +#include "extensions/browser/extension_registry.h" #include "google_apis/drive/auth_service.h" #include "google_apis/drive/drive_api_url_generator.h" #include "mojo/public/cpp/bindings/callback_helpers.h" @@ -791,6 +796,16 @@ ->network_state_handler() ->FirstNetworkByType(chromeos::NetworkTypePattern::Mobile()); + const auto& enabled_extensions = + extensions::ExtensionRegistry::Get(browser_context()) + ->enabled_extensions(); + result.can_pin_hosted_files = + base::FeatureList::IsEnabled( + chromeos::features::kDriveFsBidirectionalNativeMessaging) && + enabled_extensions.Contains(extension_misc::kDocsOfflineExtensionId) && + enabled_extensions.Contains( + GURL(drive::kDriveFsNativeMessageHostOrigins[0]).host()); + return RespondNow(ArgumentList( api::file_manager_private::GetDriveConnectionState::Results::Create( result)));
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc index ca460bf1..9072abd 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -211,8 +211,8 @@ return base::StrCat({"data:image/png;base64,", base::Base64Encode(png_data)}); } -// The maximum size of the PDF size for which thumbnails are generated. -constexpr static uint32_t kMaxPdfSize = 1024u * 1024u; +// The maximum size of the input PDF file for which thumbnails are generated. +constexpr uint32_t kMaxPdfSize = 1024u * 1024u; // A function that performs IO operations to read and render PDF thumbnail // Must be run by a blocking task runner. @@ -1150,7 +1150,7 @@ } FileManagerPrivateInternalGetThumbnailFunction:: - FileManagerPrivateInternalGetThumbnailFunction() {} + FileManagerPrivateInternalGetThumbnailFunction() = default; FileManagerPrivateInternalGetThumbnailFunction:: ~FileManagerPrivateInternalGetThumbnailFunction() = default; @@ -1290,7 +1290,7 @@ base::BindOnce(&FileManagerPrivateInternalGetThumbnailFunction:: GotDriveThumbnail, this), - base::Optional<std::vector<uint8_t>>())); + base::nullopt)); return RespondLater(); } @@ -1301,11 +1301,7 @@ return; } base::ThreadPool::PostTaskAndReplyWithResult( - FROM_HERE, - base::BindOnce( - &MakeThumbnailDataUrlOnThreadPool, - base::make_span(reinterpret_cast<const uint8_t*>(data->data()), - data->size())), + FROM_HERE, base::BindOnce(&MakeThumbnailDataUrlOnThreadPool, *data), base::BindOnce( &FileManagerPrivateInternalGetThumbnailFunction::SendEncodedThumbnail, this));
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h index 3d47181..c988ab9 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.h
@@ -13,7 +13,6 @@ #include <vector> #include "base/files/file.h" -#include "base/macros.h" #include "chrome/browser/chromeos/extensions/file_manager/private_api_base.h" #include "chrome/browser/chromeos/file_system_provider/provided_file_system_interface.h" #include "chrome/browser/extensions/chrome_extension_function_details.h" @@ -206,13 +205,18 @@ FileManagerPrivateGetProvidersFunction(); DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.getProviders", FILEMANAGERPRIVATE_GETPROVIDERS) + + FileManagerPrivateGetProvidersFunction( + const FileManagerPrivateGetProvidersFunction&) = delete; + FileManagerPrivateGetProvidersFunction& operator=( + const FileManagerPrivateGetProvidersFunction&) = delete; + protected: ~FileManagerPrivateGetProvidersFunction() override = default; private: ResponseAction Run() override; const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateGetProvidersFunction); }; // Implements the chrome.fileManagerPrivate.addProvidedFileSystem method. @@ -222,13 +226,18 @@ FileManagerPrivateAddProvidedFileSystemFunction(); DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.addProvidedFileSystem", FILEMANAGERPRIVATE_ADDPROVIDEDFILESYSTEM) + + FileManagerPrivateAddProvidedFileSystemFunction( + const FileManagerPrivateAddProvidedFileSystemFunction&) = delete; + FileManagerPrivateAddProvidedFileSystemFunction& operator=( + const FileManagerPrivateAddProvidedFileSystemFunction&) = delete; + protected: ~FileManagerPrivateAddProvidedFileSystemFunction() override = default; private: ResponseAction Run() override; const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateAddProvidedFileSystemFunction); }; // Implements the chrome.fileManagerPrivate.configureVolume method. @@ -238,6 +247,12 @@ FileManagerPrivateConfigureVolumeFunction(); DECLARE_EXTENSION_FUNCTION("fileManagerPrivate.configureVolume", FILEMANAGERPRIVATE_CONFIGUREVOLUME) + + FileManagerPrivateConfigureVolumeFunction( + const FileManagerPrivateConfigureVolumeFunction&) = delete; + FileManagerPrivateConfigureVolumeFunction& operator=( + const FileManagerPrivateConfigureVolumeFunction&) = delete; + protected: ~FileManagerPrivateConfigureVolumeFunction() override = default; @@ -246,7 +261,6 @@ void OnCompleted(base::File::Error result); const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateConfigureVolumeFunction); }; // Implements the chrome.fileManagerPrivate.mountCrostini method. @@ -257,6 +271,11 @@ FILEMANAGERPRIVATE_MOUNTCROSTINI) FileManagerPrivateMountCrostiniFunction(); + FileManagerPrivateMountCrostiniFunction( + const FileManagerPrivateMountCrostiniFunction&) = delete; + FileManagerPrivateMountCrostiniFunction& operator=( + const FileManagerPrivateMountCrostiniFunction&) = delete; + protected: ~FileManagerPrivateMountCrostiniFunction() override; @@ -266,7 +285,6 @@ private: std::string source_path_; std::string mount_label_; - DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateMountCrostiniFunction); }; // Implements the chrome.fileManagerPrivate.importCrostiniImage method. @@ -278,6 +296,11 @@ FILEMANAGERPRIVATEINTERNAL_IMPORTCROSTINIIMAGE) FileManagerPrivateInternalImportCrostiniImageFunction(); + FileManagerPrivateInternalImportCrostiniImageFunction( + const FileManagerPrivateInternalImportCrostiniImageFunction&) = delete; + FileManagerPrivateInternalImportCrostiniImageFunction& operator=( + const FileManagerPrivateInternalImportCrostiniImageFunction&) = delete; + protected: ~FileManagerPrivateInternalImportCrostiniImageFunction() override; @@ -285,8 +308,6 @@ ResponseAction Run() override; std::string image_path_; - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalImportCrostiniImageFunction); }; // Implements the chrome.fileManagerPrivate.sharePathsWithCrostini @@ -299,6 +320,11 @@ FILEMANAGERPRIVATEINTERNAL_SHAREPATHSWITHCROSTINI) FileManagerPrivateInternalSharePathsWithCrostiniFunction() = default; + FileManagerPrivateInternalSharePathsWithCrostiniFunction( + const FileManagerPrivateInternalSharePathsWithCrostiniFunction&) = delete; + FileManagerPrivateInternalSharePathsWithCrostiniFunction& operator=( + const FileManagerPrivateInternalSharePathsWithCrostiniFunction&) = delete; + protected: ~FileManagerPrivateInternalSharePathsWithCrostiniFunction() override = default; @@ -306,8 +332,6 @@ private: ResponseAction Run() override; void SharePathsCallback(bool success, const std::string& failure_reason); - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalSharePathsWithCrostiniFunction); }; // Implements the chrome.fileManagerPrivate.unsharePathWithCrostini @@ -320,6 +344,13 @@ FILEMANAGERPRIVATEINTERNAL_UNSHAREPATHWITHCROSTINI) FileManagerPrivateInternalUnsharePathWithCrostiniFunction() = default; + FileManagerPrivateInternalUnsharePathWithCrostiniFunction( + const FileManagerPrivateInternalUnsharePathWithCrostiniFunction&) = + delete; + FileManagerPrivateInternalUnsharePathWithCrostiniFunction& operator=( + const FileManagerPrivateInternalUnsharePathWithCrostiniFunction&) = + delete; + protected: ~FileManagerPrivateInternalUnsharePathWithCrostiniFunction() override = default; @@ -327,8 +358,6 @@ private: ResponseAction Run() override; void UnsharePathCallback(bool success, const std::string& failure_reason); - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalUnsharePathWithCrostiniFunction); }; // Implements the chrome.fileManagerPrivate.getCrostiniSharedPaths @@ -341,14 +370,17 @@ FILEMANAGERPRIVATEINTERNAL_GETCROSTINISHAREDPATHS) FileManagerPrivateInternalGetCrostiniSharedPathsFunction() = default; + FileManagerPrivateInternalGetCrostiniSharedPathsFunction( + const FileManagerPrivateInternalGetCrostiniSharedPathsFunction&) = delete; + FileManagerPrivateInternalGetCrostiniSharedPathsFunction operator=( + const FileManagerPrivateInternalGetCrostiniSharedPathsFunction&) = delete; + protected: ~FileManagerPrivateInternalGetCrostiniSharedPathsFunction() override = default; private: ResponseAction Run() override; - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalGetCrostiniSharedPathsFunction); }; // Implements the chrome.fileManagerPrivate.getLinuxPackageInfo method. @@ -360,6 +392,11 @@ FILEMANAGERPRIVATEINTERNAL_GETLINUXPACKAGEINFO) FileManagerPrivateInternalGetLinuxPackageInfoFunction() = default; + FileManagerPrivateInternalGetLinuxPackageInfoFunction( + const FileManagerPrivateInternalGetLinuxPackageInfoFunction&) = delete; + FileManagerPrivateInternalGetLinuxPackageInfoFunction operator=( + const FileManagerPrivateInternalGetLinuxPackageInfoFunction&) = delete; + protected: ~FileManagerPrivateInternalGetLinuxPackageInfoFunction() override = default; @@ -367,8 +404,6 @@ ResponseAction Run() override; void OnGetLinuxPackageInfo( const crostini::LinuxPackageInfo& linux_package_info); - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalGetLinuxPackageInfoFunction); }; // Implements the chrome.fileManagerPrivate.installLinuxPackage method. @@ -380,14 +415,17 @@ FILEMANAGERPRIVATEINTERNAL_INSTALLLINUXPACKAGE) FileManagerPrivateInternalInstallLinuxPackageFunction() = default; + FileManagerPrivateInternalInstallLinuxPackageFunction( + const FileManagerPrivateInternalInstallLinuxPackageFunction&) = delete; + FileManagerPrivateInternalInstallLinuxPackageFunction operator=( + const FileManagerPrivateInternalInstallLinuxPackageFunction&) = delete; + protected: ~FileManagerPrivateInternalInstallLinuxPackageFunction() override = default; private: ResponseAction Run() override; void OnInstallLinuxPackage(crostini::CrostiniResult result); - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalInstallLinuxPackageFunction); }; // Implements the chrome.fileManagerPrivate.getCustomActions method. @@ -397,6 +435,12 @@ FileManagerPrivateInternalGetCustomActionsFunction(); DECLARE_EXTENSION_FUNCTION("fileManagerPrivateInternal.getCustomActions", FILEMANAGERPRIVATEINTERNAL_GETCUSTOMACTIONS) + + FileManagerPrivateInternalGetCustomActionsFunction( + const FileManagerPrivateInternalGetCustomActionsFunction&) = delete; + FileManagerPrivateInternalGetCustomActionsFunction operator=( + const FileManagerPrivateInternalGetCustomActionsFunction&) = delete; + protected: ~FileManagerPrivateInternalGetCustomActionsFunction() override = default; @@ -406,7 +450,6 @@ base::File::Error result); const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateInternalGetCustomActionsFunction); }; // Implements the chrome.fileManagerPrivate.executeCustomAction method. @@ -416,6 +459,12 @@ FileManagerPrivateInternalExecuteCustomActionFunction(); DECLARE_EXTENSION_FUNCTION("fileManagerPrivateInternal.executeCustomAction", FILEMANAGERPRIVATEINTERNAL_EXECUTECUSTOMACTION) + + FileManagerPrivateInternalExecuteCustomActionFunction( + const FileManagerPrivateInternalExecuteCustomActionFunction&) = delete; + FileManagerPrivateInternalExecuteCustomActionFunction operator=( + const FileManagerPrivateInternalExecuteCustomActionFunction&) = delete; + protected: ~FileManagerPrivateInternalExecuteCustomActionFunction() override = default; @@ -424,8 +473,6 @@ void OnCompleted(base::File::Error result); const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN( - FileManagerPrivateInternalExecuteCustomActionFunction); }; // Implements the chrome.fileManagerPrivateInternal.getRecentFiles method. @@ -435,6 +482,12 @@ FileManagerPrivateInternalGetRecentFilesFunction(); DECLARE_EXTENSION_FUNCTION("fileManagerPrivateInternal.getRecentFiles", FILEMANAGERPRIVATE_GETRECENTFILES) + + FileManagerPrivateInternalGetRecentFilesFunction( + const FileManagerPrivateInternalGetRecentFilesFunction&) = delete; + FileManagerPrivateInternalGetRecentFilesFunction& operator=( + FileManagerPrivateInternalGetRecentFilesFunction&) = delete; + protected: ~FileManagerPrivateInternalGetRecentFilesFunction() override = default; @@ -448,7 +501,6 @@ entry_definition_list); const ChromeExtensionFunctionDetails chrome_details_; - DISALLOW_COPY_AND_ASSIGN(FileManagerPrivateInternalGetRecentFilesFunction); }; // Implements the chrome.fileManagerPrivate.detectCharacterEncoding method.
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc index ee9ff24..e3856d1a 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -67,10 +67,6 @@ dict->SetBoolean( "FILTERS_IN_RECENTS_ENABLED", base::FeatureList::IsEnabled(chromeos::features::kFiltersInRecents)); - dict->SetBoolean( - "DRIVE_BIDIRECTIONAL_NATIVE_MESSAGING_ENABLED", - base::FeatureList::IsEnabled( - chromeos::features::kDriveFsBidirectionalNativeMessaging)); dict->SetBoolean("HOLDING_SPACE_ENABLED", ash::features::IsTemporaryHoldingSpaceEnabled()); dict->SetBoolean("FILES_SINGLE_PARTITION_FORMAT_ENABLED",
diff --git a/chrome/browser/chromeos/file_manager/app_service_file_tasks.cc b/chrome/browser/chromeos/file_manager/app_service_file_tasks.cc index 4ac6943f..0c08370e 100644 --- a/chrome/browser/chromeos/file_manager/app_service_file_tasks.cc +++ b/chrome/browser/chromeos/file_manager/app_service_file_tasks.cc
@@ -137,6 +137,8 @@ /*prefer_container=*/true), launch_source, file_urls, mime_types); + // TODO(benwells): return the correct code here, depending on how the app will + // be opened in multiprofile. std::move(done).Run( extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT, ""); }
diff --git a/chrome/browser/chromeos/file_manager/arc_file_tasks.cc b/chrome/browser/chromeos/file_manager/arc_file_tasks.cc index 6aaeab0..527fc26 100644 --- a/chrome/browser/chromeos/file_manager/arc_file_tasks.cc +++ b/chrome/browser/chromeos/file_manager/arc_file_tasks.cc
@@ -290,6 +290,8 @@ ConstructOpenUrlsRequest(task, content_urls, mime_types); arc_file_system->OpenUrlsWithPermission(std::move(request), base::DoNothing()); + // TODO(benwells): return the correct code here, depending on how the app + // will be opened in multiprofile. std::move(done).Run( extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT, "");
diff --git a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc index e624f17..f9a41dc 100644 --- a/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc +++ b/chrome/browser/chromeos/file_manager/external_filesystem_apitest.cc
@@ -764,7 +764,9 @@ // gallery. IN_PROC_BROWSER_TEST_P(FileSystemExtensionApiTestWithApps, OpenGalleryForPng) { base::HistogramTester histogram_tester; - EXPECT_TRUE(RunBackgroundPageTestCase("open_gallery", "testPngOpensGallery")) + EXPECT_TRUE(RunBackgroundPageTestCase( + "open_gallery", MediaAppEnabled() ? "testPngOpensGalleryReturnsOpened" + : "testPngOpensGalleryReturnsMsgSent")) << message_; histogram_tester.ExpectBucketCount(kAppLaunchMetric, kGalleryUmaBucket, MediaAppEnabled() ? 0 : 1);
diff --git a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc index b2925d7..59136fc 100644 --- a/chrome/browser/chromeos/file_manager/file_browser_handlers.cc +++ b/chrome/browser/chromeos/file_manager/file_browser_handlers.cc
@@ -300,6 +300,9 @@ std::string failure_reason) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (done_) { + // In a multiprofile session, extension handlers will open on the desktop + // corresponding to the profile that owns the files, so return + // TASK_RESULT_MESSAGE_SENT. std::move(done_).Run( success ? extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc index b273e03..033c3d5 100644 --- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc +++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -626,6 +626,7 @@ TestCase("driveOpenSidebarSharedWithMe"), TestCase("driveAutoCompleteQuery"), TestCase("drivePinMultiple"), + TestCase("drivePinHosted"), TestCase("drivePinFileMobileNetwork"), TestCase("driveClickFirstSearchResult"), TestCase("drivePressEnterToSearch"),
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc index d82e3b2..dd7ef65 100644 --- a/chrome/browser/chromeos/file_manager/file_tasks.cc +++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -552,7 +552,9 @@ } // Some action IDs of the file manager's file browser handlers require the - // files to be directly opened with the browser. + // files to be directly opened with the browser. In a multiprofile session + // this will always open on the current desktop, regardless of which profile + // owns the files, so return TASK_RESULT_OPENED. if (ShouldBeOpenedWithBrowser(task.app_id, task.action_id)) { const bool result = OpenFilesWithBrowser(profile, file_urls, task.action_id); @@ -585,6 +587,9 @@ DCHECK(!extension->from_bookmark()); apps::LaunchPlatformAppWithFileHandler(extension_task_profile, extension, task.action_id, paths); + // In a multiprofile session, platform apps will open on the desktop + // corresponding to the profile that owns the files, so return + // TASK_RESULT_MESSAGE_SENT. if (!done.is_null()) std::move(done).Run( extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT, "");
diff --git a/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc b/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc index 6a79dfe..2a04a96f 100644 --- a/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc +++ b/chrome/browser/chromeos/file_manager/guest_os_file_tasks.cc
@@ -129,6 +129,8 @@ auto ConvertLaunchPluginVmAppResultToTaskResult( plugin_vm::LaunchPluginVmAppResult result) { + // TODO(benwells): return the correct code here, depending on how the app will + // be opened in multiprofile. namespace fmp = extensions::api::file_manager_private; switch (result) { case plugin_vm::LaunchPluginVmAppResult::SUCCESS: @@ -294,6 +296,8 @@ LOG(ERROR) << "Crostini task error: " << failure_reason; } std::move(done).Run( + // TODO(benwells): return the correct code here, depending + // on how the app will be opened in multiprofile. success ? extensions::api::file_manager_private:: TASK_RESULT_MESSAGE_SENT : extensions::api::file_manager_private::
diff --git a/chrome/browser/chromeos/file_manager/web_file_tasks.cc b/chrome/browser/chromeos/file_manager/web_file_tasks.cc index f2a83f7..a91f60d9 100644 --- a/chrome/browser/chromeos/file_manager/web_file_tasks.cc +++ b/chrome/browser/chromeos/file_manager/web_file_tasks.cc
@@ -161,8 +161,11 @@ /* preferred_containner=*/false), apps::mojom::LaunchSource::kFromFileManager, std::move(launch_files)); - std::move(done).Run( - extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT, ""); + // In a multiprofile session, web apps always open on the current desktop, + // regardless of which profile owns the files being opened, so use + // TASK_RESULT_OPENED. + std::move(done).Run(extensions::api::file_manager_private::TASK_RESULT_OPENED, + ""); } } // namespace file_tasks
diff --git a/chrome/browser/extensions/service_worker_apitest.cc b/chrome/browser/extensions/service_worker_apitest.cc index a3f5470..c8f51777d 100644 --- a/chrome/browser/extensions/service_worker_apitest.cc +++ b/chrome/browser/extensions/service_worker_apitest.cc
@@ -198,7 +198,7 @@ return ExtractInnerText(Navigate(url)); } - size_t GetWorkerRefCount(const GURL& origin) { + size_t GetWorkerRefCount(const url::Origin& origin) { content::ServiceWorkerContext* sw_context = content::BrowserContext::GetDefaultStoragePartition( browser()->profile()) @@ -2089,9 +2089,11 @@ content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); + url::Origin extension_origin = url::Origin::Create(extension->url()); + // Service worker should have no pending requests because it hasn't performed // any extension API request yet. - EXPECT_EQ(0u, GetWorkerRefCount(extension->url())); + EXPECT_EQ(0u, GetWorkerRefCount(extension_origin)); ExtensionTestMessageListener worker_listener("CHECK_REF_COUNT", true); worker_listener.set_failure_message("FAILURE"); @@ -2100,7 +2102,7 @@ // Service worker should have exactly one pending request because // chrome.test.sendMessage() API call is in-flight. - EXPECT_EQ(1u, GetWorkerRefCount(extension->url())); + EXPECT_EQ(1u, GetWorkerRefCount(extension_origin)); // Perform another extension API request while one is ongoing. { @@ -2111,7 +2113,7 @@ ASSERT_TRUE(listener.WaitUntilSatisfied()); // Service worker currently has two extension API requests in-flight. - EXPECT_EQ(2u, GetWorkerRefCount(extension->url())); + EXPECT_EQ(2u, GetWorkerRefCount(extension_origin)); // Finish executing the nested chrome.test.sendMessage() first. listener.Reply("Hello world"); } @@ -2138,7 +2140,7 @@ } // The ref count should drop to 0. - EXPECT_EQ(0u, GetWorkerRefCount(extension->url())); + EXPECT_EQ(0u, GetWorkerRefCount(extension_origin)); } const char* kEventsToStoppedExtensionId = "ogdbpbegnmindpdjfafpmpicikegejdj";
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index a9249bc..7a3218a 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -547,16 +547,6 @@ "expiry_milestone": 90 }, { - "name": "content-indexing-download-home", - "owners": [ "shaktisahu", "dtrainor" ], - "expiry_milestone": 85 - }, - { - "name": "content-indexing-ntp", - "owners": [ "shaktisahu", "dtrainor" ], - "expiry_milestone": 85 - }, - { "name": "content-settings-redesign", "owners": [ "tchudakov", @@ -1779,6 +1769,16 @@ "expiry_milestone": 82 }, { + "name": "enable-migrate-default-chrome-app-to-web-apps-gsuite", + "owners": [ "alancutter", "desktop-pwas-team@google.com" ], + "expiry_milestone": 89 + }, + { + "name": "enable-migrate-default-chrome-app-to-web-apps-non-gsuite", + "owners": [ "alancutter", "desktop-pwas-team@google.com" ], + "expiry_milestone": 89 + }, + { "name": "enable-mygoogle", "owners": [ "fernandex", "chrome-ios-signin@google.com" ], "expiry_milestone": 87
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index df84181..7fedaba3 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -709,6 +709,18 @@ "Experimental system for using the Desktop PWA framework for running System" "Apps (e.g Settings, Discover)."; +const char kEnableMigrateDefaultChromeAppToWebAppsGSuiteName[] = + "Migrate default G Suite Chrome apps to web apps"; +const char kEnableMigrateDefaultChromeAppToWebAppsGSuiteDescription[] = + "Enable the migration of default installed G Suite Chrome apps over to " + "their corresponding web apps."; + +const char kEnableMigrateDefaultChromeAppToWebAppsNonGSuiteName[] = + "Migrate default non-G Suite Chrome apps to web apps"; +const char kEnableMigrateDefaultChromeAppToWebAppsNonGSuiteDescription[] = + "Enable the migration of default installed non-G Suite Chrome apps over to " + "their corresponding web apps."; + const char kEnableTLS13EarlyDataName[] = "TLS 1.3 Early Data"; const char kEnableTLS13EarlyDataDescription[] = "This option enables TLS 1.3 Early Data, allowing GET requests to be sent " @@ -2692,15 +2704,6 @@ "A new method of persisting Tab data across restarts has been devised " "and implemented. This actives the new approach."; -const char kContentIndexingDownloadHomeName[] = - "Content indexing in download home"; -const char kContentIndexingDownloadHomeDescription[] = - "Shows content indexing articles in group cards in download home"; - -const char kContentIndexingNTPName[] = "Content indexing in NTP"; -const char kContentIndexingNTPDescription[] = - "Shows content indexing entry point UI in NTP"; - const char kContextMenuPerformanceInfoAndRemoteHintFetchingName[] = "Context menu performance info and remote hint fetching"; const char kContextMenuPerformanceInfoAndRemoteHintFetchingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 0bcb2c6..63fa9b98 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -424,6 +424,12 @@ extern const char kEnableSystemWebAppsName[]; extern const char kEnableSystemWebAppsDescription[]; +extern const char kEnableMigrateDefaultChromeAppToWebAppsGSuiteName[]; +extern const char kEnableMigrateDefaultChromeAppToWebAppsGSuiteDescription[]; + +extern const char kEnableMigrateDefaultChromeAppToWebAppsNonGSuiteName[]; +extern const char kEnableMigrateDefaultChromeAppToWebAppsNonGSuiteDescription[]; + extern const char kEnableTLS13EarlyDataName[]; extern const char kEnableTLS13EarlyDataDescription[]; @@ -1562,12 +1568,6 @@ extern const char kCriticalPersistedTabDataName[]; extern const char kCriticalPersistedTabDataDescription[]; -extern const char kContentIndexingDownloadHomeName[]; -extern const char kContentIndexingDownloadHomeDescription[]; - -extern const char kContentIndexingNTPName[]; -extern const char kContentIndexingNTPDescription[]; - extern const char kContextMenuPerformanceInfoAndRemoteHintFetchingName[]; extern const char kContextMenuPerformanceInfoAndRemoteHintFetchingDescription[];
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc index 9ff6d7c..fc48bb2 100644 --- a/chrome/browser/flags/android/chrome_feature_list.cc +++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -133,8 +133,6 @@ &kChromeSharingHubV15, &kCommandLineOnNonRooted, &kConditionalTabStripAndroid, - &kContentIndexingDownloadHome, - &kContentIndexingNTP, &kContentSuggestionsScrollToLoad, &kContextMenuEnableLensShoppingAllowlist, &kContextMenuGoogleLensChip, @@ -381,12 +379,6 @@ const base::Feature kCommandLineOnNonRooted{"CommandLineOnNonRooted", base::FEATURE_DISABLED_BY_DEFAULT}; -const base::Feature kContentIndexingDownloadHome{ - "ContentIndexingDownloadHome", base::FEATURE_ENABLED_BY_DEFAULT}; - -const base::Feature kContentIndexingNTP{"ContentIndexingNTP", - base::FEATURE_DISABLED_BY_DEFAULT}; - const base::Feature kContentSuggestionsScrollToLoad{ "ContentSuggestionsScrollToLoad", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/flags/android/chrome_feature_list.h b/chrome/browser/flags/android/chrome_feature_list.h index 2af8850..864953ee 100644 --- a/chrome/browser/flags/android/chrome_feature_list.h +++ b/chrome/browser/flags/android/chrome_feature_list.h
@@ -44,8 +44,6 @@ extern const base::Feature kChromeSharingHubV15; extern const base::Feature kCommandLineOnNonRooted; extern const base::Feature kConditionalTabStripAndroid; -extern const base::Feature kContentIndexingDownloadHome; -extern const base::Feature kContentIndexingNTP; extern const base::Feature kContextMenuEnableLensShoppingAllowlist; extern const base::Feature kContextMenuGoogleLensChip; extern const base::Feature kContextMenuPerformanceInfo;
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java index bdcc2f1..8fd17db 100644 --- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java +++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -249,8 +249,6 @@ public static final String CONTACTS_PICKER_SELECT_ALL = "ContactsPickerSelectAll"; public static final String CONTENT_SUGGESTIONS_SCROLL_TO_LOAD = "ContentSuggestionsScrollToLoad"; - public static final String CONTENT_INDEXING_NTP = "ContentIndexingNTP"; - public static final String CONTENT_INDEXING_DOWNLOAD_HOME = "ContentIndexingDownloadHome"; public static final String CONTEXT_MENU_ENABLE_LENS_SHOPPING_ALLOWLIST = "ContextMenuEnableLensShoppingAllowlist"; public static final String CONTEXT_MENU_GOOGLE_LENS_CHIP = "ContextMenuGoogleLensChip";
diff --git a/chrome/browser/memory/memory_kills_monitor.cc b/chrome/browser/memory/memory_kills_monitor.cc index 2781c1da..cc9ba5d 100644 --- a/chrome/browser/memory/memory_kills_monitor.cc +++ b/chrome/browser/memory/memory_kills_monitor.cc
@@ -4,83 +4,36 @@ #include "chrome/browser/memory/memory_kills_monitor.h" -#include <errno.h> -#include <fcntl.h> -#include <inttypes.h> -#include <stdio.h> - -#include <fstream> -#include <ios> #include <string> -#include <vector> #include "base/bind.h" -#include "base/command_line.h" -#include "base/debug/leak_annotations.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" #include "base/lazy_instance.h" -#include "base/location.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" -#include "base/posix/safe_strerror.h" -#include "base/sequenced_task_runner.h" +#include "base/process/process_metrics.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/synchronization/atomic_flag.h" -#include "base/threading/platform_thread.h" #include "chrome/browser/memory/memory_kills_histogram.h" #include "content/public/browser/browser_thread.h" -#include "third_party/re2/src/re2/re2.h" namespace memory { -using base::TimeDelta; - namespace { base::LazyInstance<MemoryKillsMonitor>::Leaky g_memory_kills_monitor_instance = LAZY_INSTANCE_INITIALIZER; -int64_t GetTimestamp(const std::string& line) { - std::vector<std::string> fields = base::SplitString( - line, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - - int64_t timestamp = -1; - // Timestamp is the third field in a line of /dev/kmsg. - if (fields.size() < 3 || !base::StringToInt64(fields[2], ×tamp)) - return -1; - return timestamp; -} - -void LogEvent(const base::Time& time_stamp, const std::string& event) { - VLOG(1) << time_stamp.ToJavaTime() << ", " << event; -} - } // namespace -MemoryKillsMonitor::Handle::Handle(MemoryKillsMonitor* outer) : outer_(outer) { - DCHECK(outer_); -} - -MemoryKillsMonitor::Handle::~Handle() { - if (outer_) { - VLOG(2) << "Chrome is shutting down" << outer_; - outer_->is_shutting_down_.Set(); - } -} - MemoryKillsMonitor::MemoryKillsMonitor() = default; MemoryKillsMonitor::~MemoryKillsMonitor() { - // The instance has to be leaked on shutdown as it is referred to by a - // non-joinable thread but ~MemoryKillsMonitor() can't be explicitly deleted - // as it overrides ~SimpleThread(), it should nevertheless never be invoked. NOTREACHED(); } // static -std::unique_ptr<MemoryKillsMonitor::Handle> MemoryKillsMonitor::Initialize() { +void MemoryKillsMonitor::Initialize() { VLOG(2) << "MemoryKillsMonitor::Initializing on " << base::PlatformThread::CurrentId(); @@ -91,11 +44,6 @@ login_state->AddObserver(g_memory_kills_monitor_instance.Pointer()); else LOG(ERROR) << "LoginState is not initialized"; - - // The MemoryKillsMonitor::Handle will notify the MemoryKillsMonitor - // when it is destroyed so that the underlying thread can at a minimum not - // do extra work during shutdown. - return std::make_unique<Handle>(g_memory_kills_monitor_instance.Pointer()); } // static @@ -107,48 +55,6 @@ type, estimated_freed_kb); } -// static -void MemoryKillsMonitor::TryMatchOomKillLine(const std::string& line) { - // Sample OOM log line: - // 3,1362,97646497541,-;Out of memory: Kill process 29582 (android.vending) - // score 961 or sacrifice child. - - // Precompile the regex object since the pattern is constant. - static const LazyRE2 kOomKillPattern = { - R"(Out of memory: Kill process .* score \d+)"}; - if (RE2::PartialMatch(line, *kOomKillPattern)) { - g_memory_kills_monitor_instance.Get().LogOOMKill(); - } -} - -// TODO(cylee): Consider adding a unit test for this fuction. -void MemoryKillsMonitor::Run() { - VLOG(2) << "Started monitoring OOM kills on thread " - << base::PlatformThread::CurrentId(); - - std::ifstream kmsg_stream("/dev/kmsg", std::ifstream::in); - if (kmsg_stream.fail()) { - LOG(WARNING) << "Open /dev/kmsg failed: " << base::safe_strerror(errno); - return; - } - // Skip kernel messages prior to the instantiation of this object to avoid - // double reporting. - // Note: there's a small gap between login the fseek here, and events in that - // period will not be recorded. - kmsg_stream.seekg(0, std::ios_base::end); - - std::string line; - while (std::getline(kmsg_stream, line)) { - if (is_shutting_down_.IsSet()) { - // Not guaranteed to execute when the process is shutting down, - // because the thread might be blocked in fgets(). - VLOG(1) << "Chrome is shutting down, MemoryKillsMonitor exits."; - break; - } - TryMatchOomKillLine(line); - } -} - void MemoryKillsMonitor::LoggedInStateChanged() { VLOG(2) << "LoggedInStateChanged"; auto* login_state = chromeos::LoginState::Get(); @@ -177,12 +83,46 @@ UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", 0, 1, 1000, 1001); UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.LowMemoryKiller.Count", 0, 1, 1000, 1001); - base::SimpleThread::Options non_joinable_options; - non_joinable_options.joinable = false; - non_joinable_worker_thread_ = std::make_unique<base::DelegateSimpleThread>( - this, "memory_kills_monitor", non_joinable_options); - non_joinable_worker_thread_->StartAsync(); monitoring_started_.Set(); + + base::VmStatInfo vmstat; + if (base::GetVmStatInfo(&vmstat)) { + last_oom_kills_count_ = vmstat.oom_kill; + } else { + last_oom_kills_count_ = 0; + } + + checking_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), + base::BindRepeating(&MemoryKillsMonitor::CheckOOMKill, + base::Unretained(this))); +} + +void MemoryKillsMonitor::CheckOOMKill() { + base::VmStatInfo vmstat; + if (base::GetVmStatInfo(&vmstat)) { + CheckOOMKillImpl(vmstat.oom_kill); + } +} + +void MemoryKillsMonitor::CheckOOMKillImpl(unsigned long current_oom_kills) { + DCHECK(monitoring_started_.IsSet()); + + unsigned long oom_kills_increased = current_oom_kills - last_oom_kills_count_; + if (oom_kills_increased == 0) + return; + + VLOG(1) << "OOM_KILLS " << oom_kills_increased << " times"; + + for (int i = 0; i < oom_kills_increased; ++i) { + ++oom_kills_count_; + + // Report the cumulative count of killed process in one login session. For + // example if there are 3 processes killed, it would report 1 for the first + // kill, 2 for the second kill, then 3 for the final kill. + UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", oom_kills_count_, 1, 1000, + 1001); + } + last_oom_kills_count_ = current_oom_kills; } void MemoryKillsMonitor::LogLowMemoryKillImpl(const std::string& type, @@ -195,12 +135,12 @@ return; } - base::Time now = base::Time::Now(); - LogEvent(now, "LOW_MEMORY_KILL_" + type); + VLOG(1) << "LOW_MEMORY_KILL_" << type; - const TimeDelta time_delta = last_low_memory_kill_time_.is_null() - ? kMaxMemoryKillTimeDelta - : (now - last_low_memory_kill_time_); + base::Time now = base::Time::Now(); + const base::TimeDelta time_delta = last_low_memory_kill_time_.is_null() + ? kMaxMemoryKillTimeDelta + : (now - last_low_memory_kill_time_); UMA_HISTOGRAM_MEMORY_KILL_TIME_INTERVAL("Arc.LowMemoryKiller.TimeDelta", time_delta); last_low_memory_kill_time_ = now; @@ -212,33 +152,6 @@ UMA_HISTOGRAM_MEMORY_KB("Arc.LowMemoryKiller.FreedSize", estimated_freed_kb); } -void MemoryKillsMonitor::LogOOMKill() { - if (!monitoring_started_.IsSet()) { - LOG(WARNING) << "LogOOMKill before monitoring started, " - "skipped this log."; - return; - } - - // Ideally the timestamp should be parsed from /dev/kmsg, but the timestamp - // there is the elapsed time since system boot. So the timestamp |now| used - // here is a bit delayed. - base::Time now = base::Time::Now(); - LogEvent(now, "OOM_KILL"); - - ++oom_kills_count_; - // Report the cumulative count of killed process in one login session. - // For example if there are 3 processes killed, it would report 1 for the - // first kill, 2 for the second kill, then 3 for the final kill. - // It doesn't report a final count at the end of a user session because - // the code runs in a dedicated thread and never ends until browser shutdown - // (or logout on Chrome OS). And on browser shutdown the thread may be - // terminated brutally so there's no chance to execute a "final" block. - // More specifically, code outside the main loop of MemoryKillsMonitor::Run() - // are not guaranteed to be executed. - UMA_HISTOGRAM_CUSTOM_COUNTS("Arc.OOMKills.Count", oom_kills_count_, 1, 1000, - 1001); -} - MemoryKillsMonitor* MemoryKillsMonitor::GetForTesting() { return g_memory_kills_monitor_instance.Pointer(); }
diff --git a/chrome/browser/memory/memory_kills_monitor.h b/chrome/browser/memory/memory_kills_monitor.h index 13e4111..ac86142d 100644 --- a/chrome/browser/memory/memory_kills_monitor.h +++ b/chrome/browser/memory/memory_kills_monitor.h
@@ -5,17 +5,11 @@ #ifndef CHROME_BROWSER_MEMORY_MEMORY_KILLS_MONITOR_H_ #define CHROME_BROWSER_MEMORY_MEMORY_KILLS_MONITOR_H_ -#include <memory> #include <string> -#include "base/files/scoped_file.h" -#include "base/gtest_prod_util.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" #include "base/synchronization/atomic_flag.h" -#include "base/synchronization/lock.h" -#include "base/threading/simple_thread.h" #include "base/time/time.h" +#include "base/timer/timer.h" #include "chromeos/login/login_state/login_state.h" namespace memory { @@ -25,93 +19,64 @@ // the chrome process has ended (usually because of a user log out). Thus it can // be deemed as a per user session logger. // -// For OOM kill events, it listens to kernel message (/dev/kmsg) in a blocking -// manner. It runs in a non-joinable thread in order to avoid blocking shutdown. -// There should be only one MemoryKillsMonitor instance globally at any given -// time, otherwise UMA would receive duplicate events. +// For OOM kill events, it checks the oom_kill field in /proc/vmstat +// periodically. There should be only one MemoryKillsMonitor instance globally +// at any given time, otherwise UMA would receive duplicate events. // // For Low memory kills events, chrome calls the single global instance of -// MemoryKillsMonitor synchronously. Note that it would be from a browser thread -// other than the listening thread. -class MemoryKillsMonitor : public base::DelegateSimpleThread::Delegate, - public chromeos::LoginState::Observer { +// MemoryKillsMonitor synchronously. Note that it must be called on the browser +// UI thread. +class MemoryKillsMonitor : public chromeos::LoginState::Observer { public: - class Handle { - public: - // Constructs a handle that will flag |outer| as shutting down on - // destruction. - explicit Handle(MemoryKillsMonitor* outer); - - ~Handle(); - - private: - MemoryKillsMonitor* const outer_; - - DISALLOW_COPY_AND_ASSIGN(Handle); - }; - MemoryKillsMonitor(); ~MemoryKillsMonitor() override; // Initializes the global instance, but do not start monitoring until user - // log in. The caller is responsible for deleting the returned handle to - // indicate the end of monitoring. - static std::unique_ptr<Handle> Initialize(); + // log in. + static void Initialize(); // A convenient function to log a low memory kill event. It only logs events // after StartMonitoring() has been called. static void LogLowMemoryKill(const std::string& type, int estimated_freed_kb); - // Gets the global instance for unit test. - static MemoryKillsMonitor* GetForTesting(); - private: FRIEND_TEST_ALL_PREFIXES(MemoryKillsMonitorTest, TestHistograms); - // Try to match a line in kernel message which reports OOM. - static void TryMatchOomKillLine(const std::string& line); - - // Overridden from base::DelegateSimpleThread::Delegate: - void Run() override; + // Gets the global instance for unit test. + static MemoryKillsMonitor* GetForTesting(); // LoginState::Observer overrides. void LoggedInStateChanged() override; - // Starts a non-joinable thread to monitor OOM kills. This must only - // be invoked once per process. + // Starts monitoring OOM kills. void StartMonitoring(); // Logs low memory kill event. void LogLowMemoryKillImpl(const std::string& type, int estimated_freed_kb); - // Logs OOM kill event. - void LogOOMKill(); + // Checks system OOM count. + void CheckOOMKill(); + + // Split CheckOOMKill and CheckOOMKillImpl for testing. + void CheckOOMKillImpl(unsigned long current_oom_kills); // A flag set when StartMonitoring() is called to indicate that monitoring has // been started. base::AtomicFlag monitoring_started_; - // A flag set when MemoryKillsMonitor is shutdown so that its thread can poll - // it and attempt to wind down from that point (to avoid unnecessary work, not - // because it blocks shutdown). - base::AtomicFlag is_shutting_down_; - - // The underlying worker thread which is non-joinable to avoid blocking - // shutdown. - std::unique_ptr<base::DelegateSimpleThread> non_joinable_worker_thread_; - // The last time a low memory kill happens. Accessed from UI thread only. base::Time last_low_memory_kill_time_; // The number of low memory kills since monitoring is started. Accessed from // UI thread only. int low_memory_kills_count_ = 0; - // The last time an OOM kill happens. Accessed from - // |non_joinable_worker_thread_| only. - int64_t last_oom_kill_time_ = -1; - // The number of OOM kills since monitoring is started. Accessed from - // |non_joinable_worker_thread_| only. - int oom_kills_count_ = 0; + // The number of OOM kills since monitoring is started. + unsigned long oom_kills_count_ = 0; + + // The last oom kills count from |GetCurrentOOMKills|. + unsigned long last_oom_kills_count_ = 0; + + base::RepeatingTimer checking_timer_; DISALLOW_COPY_AND_ASSIGN(MemoryKillsMonitor); };
diff --git a/chrome/browser/memory/memory_kills_monitor_unittest.cc b/chrome/browser/memory/memory_kills_monitor_unittest.cc index f389707f..df0c6a4 100644 --- a/chrome/browser/memory/memory_kills_monitor_unittest.cc +++ b/chrome/browser/memory/memory_kills_monitor_unittest.cc
@@ -108,18 +108,9 @@ } // OOM kills. - const char* sample_lines[] = { - "3,3429,812967386,-;Out of memory: Kill process 8291 (handle-watcher-) " - "score 674 or sacrifice child", - "3,3431,812981331,-;Out of memory: Kill process 8271 (.gms.persistent) " - "score 652 or sacrifice child", - "3,3433,812993014,-;Out of memory: Kill process 9210 (lowpool[11]) " - "score 653 or sacrifice child" - }; - - for (unsigned long i = 0; i < base::size(sample_lines); ++i) { - MemoryKillsMonitor::TryMatchOomKillLine(sample_lines[i]); - } + // Simulate getting 3 more oom kills. + g_memory_kills_monitor_unittest_instance->CheckOOMKillImpl( + g_memory_kills_monitor_unittest_instance->last_oom_kills_count_ + 3); oom_count_histogram = GetOOMKillsCountHistogram(); ASSERT_TRUE(oom_count_histogram); @@ -133,15 +124,6 @@ EXPECT_EQ(1, count_samples->GetCount(3)); } - // Call StartMonitoring multiple times. - base::DelegateSimpleThread* thread1 = g_memory_kills_monitor_unittest_instance - ->non_joinable_worker_thread_.get(); - EXPECT_NE(nullptr, thread1); - g_memory_kills_monitor_unittest_instance->StartMonitoring(); - base::DelegateSimpleThread* thread2 = g_memory_kills_monitor_unittest_instance - ->non_joinable_worker_thread_.get(); - EXPECT_EQ(thread1, thread2); - lmk_count_histogram = GetLowMemoryKillsCountHistogram(); ASSERT_TRUE(lmk_count_histogram); {
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc index 1a036e9..4113bc1 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.cc
@@ -21,7 +21,6 @@ #include "chrome/browser/nearby_sharing/client/nearby_share_client.h" #include "chrome/browser/nearby_sharing/common/nearby_share_http_result.h" #include "chrome/browser/nearby_sharing/common/nearby_share_prefs.h" -#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h" #include "chrome/browser/nearby_sharing/logging/logging.h" #include "chrome/browser/nearby_sharing/proto/certificate_rpc.pb.h" #include "chrome/browser/nearby_sharing/proto/encrypted_metadata.pb.h" @@ -234,10 +233,12 @@ /*page_number=*/1, /*certificate_count=*/0), clock_)) { + local_device_data_manager_->AddObserver(this); contact_manager_->AddObserver(this); } NearbyShareCertificateManagerImpl::~NearbyShareCertificateManagerImpl() { + local_device_data_manager_->RemoveObserver(this); contact_manager_->RemoveObserver(this); } @@ -303,7 +304,7 @@ return; certificate_storage_->ClearPrivateCertificates(); - private_certificate_expiration_scheduler_->Reschedule(); + private_certificate_expiration_scheduler_->MakeImmediateRequest(); } void NearbyShareCertificateManagerImpl::OnContactsDownloaded( @@ -316,7 +317,18 @@ return; certificate_storage_->ClearPrivateCertificates(); - private_certificate_expiration_scheduler_->Reschedule(); + private_certificate_expiration_scheduler_->MakeImmediateRequest(); +} + +void NearbyShareCertificateManagerImpl::OnLocalDeviceDataChanged( + bool did_device_name_change, + bool did_full_name_change, + bool did_icon_url_change) { + if (!did_device_name_change && !did_full_name_change && !did_icon_url_change) + return; + + certificate_storage_->ClearPrivateCertificates(); + private_certificate_expiration_scheduler_->MakeImmediateRequest(); } base::Optional<base::Time>
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h index f6c8e78..75d86c2 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h
@@ -22,6 +22,7 @@ #include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h" #include "chrome/browser/nearby_sharing/common/nearby_share_http_result.h" #include "chrome/browser/nearby_sharing/contacts/nearby_share_contact_manager.h" +#include "chrome/browser/nearby_sharing/local_device_data/nearby_share_local_device_data_manager.h" #include "chrome/browser/nearby_sharing/proto/rpc_resources.pb.h" #include "chrome/browser/ui/webui/nearby_share/public/mojom/nearby_share_settings.mojom.h" @@ -64,7 +65,8 @@ // interface for performing cryptographic operations related to certificates." class NearbyShareCertificateManagerImpl : public NearbyShareCertificateManager, - public NearbyShareContactManager::Observer { + public NearbyShareContactManager::Observer, + public NearbyShareLocalDeviceDataManager::Observer { public: class Factory { public: @@ -126,6 +128,11 @@ const std::vector<nearbyshare::proto::ContactRecord>& contacts) override; void OnContactsUploaded(bool did_contacts_change_since_last_upload) override; + // NearbyShareLocalDeviceDataManager::Observer: + void OnLocalDeviceDataChanged(bool did_device_name_change, + bool did_full_name_change, + bool did_icon_url_change) override; + // Used by the private certificate expiration scheduler to determine the next // private certificate expiration time. Returns base::Time::Min() if // certificates are missing. This function never returns base::nullopt.
diff --git a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc index 529c57f6..8f9037a 100644 --- a/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc +++ b/chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl_unittest.cc
@@ -68,6 +68,15 @@ NearbyShareCertificateStorageImpl::Factory::SetFactoryForTesting( &cert_store_factory_); + // Set default device data. + local_device_data_manager_->SetDeviceName( + GetNearbyShareTestMetadata().device_name()); + local_device_data_manager_->SetFullName( + GetNearbyShareTestMetadata().full_name()); + local_device_data_manager_->SetIconUrl( + GetNearbyShareTestMetadata().icon_url()); + SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); + cert_manager_ = NearbyShareCertificateManagerImpl::Factory::Create( local_device_data_manager_.get(), contact_manager_.get(), pref_service_.get(), @@ -497,14 +506,6 @@ RefreshPrivateCertificates_ValidCertificates) { cert_store_->SetPrivateCertificates(private_certificates_); - local_device_data_manager_->SetDeviceName( - GetNearbyShareTestMetadata().device_name()); - local_device_data_manager_->SetFullName( - GetNearbyShareTestMetadata().full_name()); - local_device_data_manager_->SetIconUrl( - GetNearbyShareTestMetadata().icon_url()); - SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); - cert_manager_->Start(); HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/false, /*expected_success=*/true); @@ -516,14 +517,6 @@ cert_store_->SetPrivateCertificates( std::vector<NearbySharePrivateCertificate>()); - local_device_data_manager_->SetDeviceName( - GetNearbyShareTestMetadata().device_name()); - local_device_data_manager_->SetFullName( - GetNearbyShareTestMetadata().full_name()); - local_device_data_manager_->SetIconUrl( - GetNearbyShareTestMetadata().icon_url()); - SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); - cert_manager_->Start(); HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true, /*expected_success=*/true); @@ -536,14 +529,6 @@ cert_store_->SetPrivateCertificates( std::vector<NearbySharePrivateCertificate>()); - local_device_data_manager_->SetDeviceName( - GetNearbyShareTestMetadata().device_name()); - local_device_data_manager_->SetFullName( - GetNearbyShareTestMetadata().full_name()); - local_device_data_manager_->SetIconUrl( - GetNearbyShareTestMetadata().icon_url()); - SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); - cert_manager_->Start(); HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true, /*expected_success=*/true); @@ -555,8 +540,8 @@ RevokePrivateCertificates_OnAllowlistChanged) { cert_manager_->Start(); - // Destroy and recreate private certificates if and only if contacts were - // removed from the user's list of selected contacts. + // Destroy and recreate private certificates if contacts were removed from the + // user's list of selected contacts. size_t num_expected_calls = 0; for (bool were_contacts_added_to_allowlist : {true, false}) { for (bool were_contacts_removed_from_allowlist : {true, false}) { @@ -569,7 +554,7 @@ EXPECT_EQ(num_expected_calls, cert_store_->num_clear_private_certificates_calls()); EXPECT_EQ(num_expected_calls, - private_cert_exp_scheduler_->num_reschedule_calls()); + private_cert_exp_scheduler_->num_immediate_requests()); } } } @@ -578,8 +563,8 @@ RevokePrivateCertificates_OnContactsUploaded) { cert_manager_->Start(); - // Destroy and recreate private certificates if and only if the user's contact - // list has changed since the last upload. + // Destroy and recreate private certificates if the user's contact list has + // changed since the last upload. size_t num_expected_calls = 0; for (bool did_contacts_change_since_last_upload : {true, false}) { contact_manager_->NotifyContactsUploaded( @@ -590,7 +575,33 @@ EXPECT_EQ(num_expected_calls, cert_store_->num_clear_private_certificates_calls()); EXPECT_EQ(num_expected_calls, - private_cert_exp_scheduler_->num_reschedule_calls()); + private_cert_exp_scheduler_->num_immediate_requests()); + } +} + +TEST_F(NearbyShareCertificateManagerImplTest, + RefreshPrivateCertificates_OnLocalDeviceMetadataChanged) { + cert_manager_->Start(); + + // Destroy and recreate private certificates if any metadata fields change. + size_t num_expected_calls = 0; + for (bool did_device_name_change : {true, false}) { + for (bool did_full_name_change : {true, false}) { + for (bool did_icon_url_change : {true, false}) { + local_device_data_manager_->NotifyLocalDeviceDataChanged( + did_device_name_change, did_full_name_change, did_icon_url_change); + + if (did_device_name_change || did_full_name_change || + did_icon_url_change) { + ++num_expected_calls; + } + + EXPECT_EQ(num_expected_calls, + cert_store_->num_clear_private_certificates_calls()); + EXPECT_EQ(num_expected_calls, + private_cert_exp_scheduler_->num_immediate_requests()); + } + } } } @@ -600,14 +611,6 @@ FastForward(kNearbyShareCertificateValidityPeriod * 1.5); cert_store_->SetPrivateCertificates(private_certificates_); - local_device_data_manager_->SetDeviceName( - GetNearbyShareTestMetadata().device_name()); - local_device_data_manager_->SetFullName( - GetNearbyShareTestMetadata().full_name()); - local_device_data_manager_->SetIconUrl( - GetNearbyShareTestMetadata().icon_url()); - SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); - cert_manager_->Start(); HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true, /*expected_success=*/true); @@ -621,11 +624,7 @@ std::vector<NearbySharePrivateCertificate>()); // Device name is missing in local device data manager. - local_device_data_manager_->SetFullName( - GetNearbyShareTestMetadata().full_name()); - local_device_data_manager_->SetIconUrl( - GetNearbyShareTestMetadata().icon_url()); - SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); + local_device_data_manager_->SetDeviceName(std::string()); cert_manager_->Start(); @@ -640,12 +639,6 @@ std::vector<NearbySharePrivateCertificate>()); // The bluetooth adapter returns an invalid Bluetooth MAC address. - local_device_data_manager_->SetDeviceName( - GetNearbyShareTestMetadata().device_name()); - local_device_data_manager_->SetFullName( - GetNearbyShareTestMetadata().full_name()); - local_device_data_manager_->SetIconUrl( - GetNearbyShareTestMetadata().icon_url()); SetBluetoothMacAddress("invalid_mac_address"); cert_manager_->Start(); @@ -666,9 +659,8 @@ std::vector<NearbySharePrivateCertificate>()); // Full name and icon URL are missing in local device data manager. - local_device_data_manager_->SetDeviceName( - GetNearbyShareTestMetadata().device_name()); - SetBluetoothMacAddress(kTestUnparsedBluetoothMacAddress); + local_device_data_manager_->SetFullName(base::nullopt); + local_device_data_manager_->SetIconUrl(base::nullopt); cert_manager_->Start(); HandlePrivateCertificateRefresh(/*expect_private_cert_refresh=*/true,
diff --git a/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h b/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h index 2fc7248..ccecfb89 100644 --- a/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h +++ b/chrome/browser/nearby_sharing/local_device_data/fake_nearby_share_local_device_data_manager.h
@@ -90,6 +90,10 @@ std::vector<nearbyshare::proto::PublicCertificate> certificates, UploadCompleteCallback callback) override; + // Make protected observer-notification methods from base class public in this + // fake class. + using NearbyShareLocalDeviceDataManager::NotifyLocalDeviceDataChanged; + void SetId(const std::string& id) { id_ = id; } void SetFullName(const base::Optional<std::string>& full_name); void SetIconUrl(const base::Optional<std::string>& icon_url);
diff --git a/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc b/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc index 727bead..73eb1a3 100644 --- a/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc +++ b/chrome/browser/password_manager/android/save_password_infobar_delegate_android.cc
@@ -95,7 +95,7 @@ InfoBarButton button) const { return l10n_util::GetStringUTF16((button == BUTTON_OK) ? IDS_PASSWORD_MANAGER_SAVE_BUTTON - : IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON); + : IDS_PASSWORD_MANAGER_BLOCKLIST_BUTTON); } bool SavePasswordInfoBarDelegate::Accept() {
diff --git a/chrome/browser/resources/settings/chromeos/lazy_load.js b/chrome/browser/resources/settings/chromeos/lazy_load.js index 5491ea4..1da38189d 100644 --- a/chrome/browser/resources/settings/chromeos/lazy_load.js +++ b/chrome/browser/resources/settings/chromeos/lazy_load.js
@@ -9,6 +9,7 @@ import './os_files_page/os_files_page.m.js'; import './os_languages_page/input_method_options_page.m.js'; import './os_languages_page/input_page.m.js'; +import './os_languages_page/os_edit_dictionary_page.m.js'; import './os_languages_page/os_languages_page.m.js'; import './os_languages_page/os_languages_page_v2.m.js'; import './os_languages_page/os_languages_section.m.js';
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn b/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn index 64813b4..865a0c63 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/BUILD.gn
@@ -16,6 +16,7 @@ ":languages_metrics_proxy", ":manage_input_methods_page", ":os_add_languages_dialog", + ":os_edit_dictionary_page", ":os_languages_page", ":os_languages_page_v2", ":os_languages_section", @@ -79,6 +80,16 @@ externs_list = [ "$externs_path/language_settings_private.js" ] } +js_library("os_edit_dictionary_page") { + deps = [ + "..:os_route", + "../..:global_scroll_target_behavior", + "../../languages_page:languages_browser_proxy", + "//ui/webui/resources/cr_elements/cr_button:cr_button", + "//ui/webui/resources/cr_elements/cr_input:cr_input", + ] +} + js_library("os_languages_section") { deps = [ ":input_method_options_page", @@ -172,6 +183,7 @@ ":languages_metrics_proxy.m", ":manage_input_methods_page.m", ":os_add_languages_dialog.m", + ":os_edit_dictionary_page.m", ":os_languages_page.m", ":os_languages_page_v2.m", ":os_languages_section.m", @@ -219,6 +231,7 @@ ":add_input_methods_dialog.m", ":input_method_util.m", ":languages_metrics_proxy.m", + ":os_edit_dictionary_page.m", "..:deep_linking_behavior.m", "..:os_route.m", "../..:i18n_setup", @@ -256,6 +269,20 @@ extra_deps = [ ":os_add_languages_dialog_module" ] } +js_library("os_edit_dictionary_page.m") { + sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.m.js" ] + deps = [ + "..:os_route.m", + "../..:global_scroll_target_behavior.m", + "../../languages_page:languages_browser_proxy.m", + "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_elements/cr_button:cr_button.m", + "//ui/webui/resources/cr_elements/cr_input:cr_input.m", + ] + extra_deps = [ ":os_edit_dictionary_page_module" ] +} + js_library("os_languages_page.m") { sources = [ "$root_gen_dir/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.m.js" ] deps = [ @@ -348,6 +375,7 @@ ":manage_input_methods_page_module", ":modulize", ":os_add_languages_dialog_module", + ":os_edit_dictionary_page_module", ":os_languages_page_module", ":os_languages_page_v2_module", ":os_languages_section_module", @@ -394,6 +422,15 @@ auto_imports = os_settings_auto_imports } +polymer_modulizer("os_edit_dictionary_page") { + js_file = "os_edit_dictionary_page.js" + html_file = "os_edit_dictionary_page.html" + html_type = "dom-module" + migrated_imports = settings_migrated_imports + namespace_rewrites = os_settings_namespace_rewrites + auto_imports = os_settings_auto_imports +} + polymer_modulizer("os_languages_page") { js_file = "os_languages_page.js" html_file = "os_languages_page.html"
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html index 74615209..a131b3c 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.html
@@ -10,6 +10,7 @@ <link rel="import" href="add_input_methods_dialog.html"> <link rel="import" href="input_method_util.html"> <link rel="import" href="languages_metrics_proxy.html"> +<link rel="import" href="os_edit_dictionary_page.html"> <link rel="import" href="remove_input_method_dialog.html"> <link rel="import" href="../deep_linking_behavior.html"> <link rel="import" href="../os_route.html"> @@ -18,6 +19,7 @@ <link rel="import" href="../../i18n_setup.html"> <link rel="import" href="../../router.html"> <link rel="import" href="../../settings_shared_css.html"> +<link rel="import" href="../../settings_page/settings_animated_pages.html"> <dom-module id="os-settings-input-page"> <template> @@ -42,6 +44,11 @@ pointer-events: none; } + /* Paddings when showing download error */ + .name-with-error { + padding: 14px 0; + } + .name-with-error div { color: var(--settings-error-color); margin-top: 8px; @@ -111,7 +118,7 @@ <div class$="list-item [[getInputMethodItemClass_( item.id, languages.inputMethods.currentId)]]" actionable on-click="onInputMethodClick_" - on-keypress="onInputMethodKeyPress_" + on-keypress="onInputMethodKeyPress_" tabindex$="[[getInputMethodTabIndex_( item.id, languages.inputMethods.currentId)]]" aria-labelledby$="language-[[index]]" role="button"> @@ -226,6 +233,7 @@ disabled="[[!prefs.browser.enable_spellchecking.value]]"> </settings-toggle-button> <cr-link-row class="hr" label="$i18n{editDictionaryLabel}" + on-click="onEditDictionaryClick_" id="editDictionarySubpageTrigger" disabled="[[!prefs.browser.enable_spellchecking.value]]" role-description="$i18n{subpageArrowRoleDescription}">
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js index 1c3c7c1f..0c35df2 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/input_page.js
@@ -23,6 +23,12 @@ notify: true, }, + /** @type {!Map<string, (string|Function)>} */ + focusConfig: { + type: Object, + observer: 'focusConfigChanged_', + }, + /** * Read-only reference to the languages model provided by the * 'os-settings-languages' instance. @@ -98,6 +104,20 @@ }, /** + * @param {!Map<string, (string|Function)>} newConfig + * @param {?Map<string, (string|Function)>} oldConfig + * @private + */ + focusConfigChanged_(newConfig, oldConfig) { + // focusConfig is set only once on the parent, so this observer should + // only fire once. + assert(!oldConfig); + this.focusConfig.set( + settings.routes.OS_LANGUAGES_EDIT_DICTIONARY.path, + () => cr.ui.focusWithoutInk(this.$.editDictionarySubpageTrigger)); + }, + + /** * @param {!Event} e * @private */ @@ -365,5 +385,16 @@ return this.i18n( 'languagesDictionaryDownloadRetryDescription', item.language.displayName); + }, + + /** + * Opens the Custom Dictionary page. + * @private + */ + onEditDictionaryClick_() { + this.languagesMetricsProxy_.recordInteraction( + settings.LanguagesPageInteraction.OPEN_CUSTOM_SPELL_CHECK); + settings.Router.getInstance().navigateTo( + settings.routes.OS_LANGUAGES_EDIT_DICTIONARY); } });
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.html new file mode 100644 index 0000000..adb98042 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.html
@@ -0,0 +1,88 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys/iron-a11y-keys.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> +<link rel="import" href="../metrics_recorder.html"> +<link rel="import" href="../os_route.html"> +<link rel="import" href="../../global_scroll_target_behavior.html"> +<link rel="import" href="../../settings_shared_css.html"> +<link rel="import" href="../../languages_page/languages_browser_proxy.html"> + +<dom-module id="os-settings-edit-dictionary-page"> + <template> + <style include="settings-shared"> + :host { + display: flex; + flex-direction: column; + } + + #newWord { + width: 100%; + --cr-input-width: 216px; + } + + #newWord::part(row-container) { + justify-content: normal; + } + + iron-list .word { + flex: 1; + padding-inline-start: 10px; + } + + #list { + padding: 0 var(--cr-section-padding); + } + + .list-item { + border-bottom: var(--cr-separator-line); + } + + #noWordsLabel { + padding-top: 39px; + text-align: center; + } + </style> + <div class="cr-row continuation"> + $i18n{editDictionaryDescription} + </div> + <div class="cr-row first"> + <iron-a11y-keys id="keys" keys="enter esc" + on-keys-pressed="onKeysPress_"> + </iron-a11y-keys> + <cr-input id="newWord" value="{{newWordValue_}}" + invalid="[[isNewWordInvalid_(newWordState_)]]" + error-message="[[getErrorMessage_(newWordState_)]]" + spellcheck="false"> + <cr-button on-click="onAddWordTap_" id="addWord" slot="suffix" + disabled="[[disableAddButton_]]"> + $i18n{addDictionaryWordButtonLabel} + </cr-button> + </cr-input> + </div> + <iron-list id="list" items="[[words_]]" preserve-focus + scroll-target="[[subpageScrollTarget]]" risk-selection> + <template> + <div class="list-item"> + <div id$="word[[index]]" class="word text-elide" aria-hidden="true"> + [[item]] + </div> + <cr-icon-button class="icon-clear" on-click="onRemoveWordTap_" + tabindex$="[[tabIndex]]" + title="$i18n{deleteDictionaryWordTooltip}" + aria-describedby$="word[[index]]"> + </cr-icon-button> + </div> + </template> + </iron-list> + <div id="noWordsLabel" class="secondary" hidden="[[hasWords_]]"> + $i18n{noDictionaryWordsLabel} + </div> + </template> + <script src="os_edit_dictionary_page.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.js new file mode 100644 index 0000000..14f7565 --- /dev/null +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.js
@@ -0,0 +1,234 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'os-settings-edit-dictionary-page' is a sub-page for editing + * the "dictionary" of custom words used for spell check. + */ + +// clang-format off +// #import {GlobalScrollTargetBehavior} from '../../global_scroll_target_behavior.m.js'; +// #import {loadTimeData} from '../../i18n_setup.js'; +// #import {PrefsBehavior} from '../../prefs/prefs_behavior.m.js'; +// #import {LanguagesBrowserProxyImpl} from '../../languages_page/languages_browser_proxy.m.js'; +// clang-format on + +// Max valid word size, keep in sync with kMaxCustomDictionaryWordBytes in +// //components/spellcheck/common/spellcheck_common.h +const MAX_CUSTOM_DICTIONARY_WORD_BYTES = 99; + +/** @enum {number} */ +const NewWordState = { + NO_WORD: 0, + VALID_WORD: 1, + WORD_ALREADY_ADDED: 2, + WORD_TOO_LONG: 3, +}; + +Polymer({ + is: 'os-settings-edit-dictionary-page', + + behaviors: [ + I18nBehavior, + settings.GlobalScrollTargetBehavior, + ], + + properties: { + /** @private */ + newWordValue_: { + type: String, + value: '', + }, + + /** + * Needed for GlobalScrollTargetBehavior. + * @override + */ + subpageRoute: { + type: Object, + value: settings.routes.OS_LANGUAGES_EDIT_DICTIONARY, + }, + + /** @private {!Array<string>} */ + words_: { + type: Array, + value: [], + }, + + /** @private */ + hasWords_: { + type: Boolean, + value: false, + computed: 'computeHasWords_(words_.length)', + }, + + /** @private */ + disableAddButton_: { + type: Boolean, + value: true, + computed: 'shouldDisableAddButton_(newWordState_)', + }, + + /** @private */ + newWordState_: { + type: Number, + value: NewWordState.NO_WORD, + computed: 'updateNewWordState_(newWordValue_, words_.*)', + } + }, + + /** @private {?LanguageSettingsPrivate} */ + languageSettingsPrivate_: null, + + /** @override */ + created() { + this.languageSettingsPrivate_ = + settings.LanguagesBrowserProxyImpl.getInstance() + .getLanguageSettingsPrivate(); + }, + + /** @override */ + ready() { + this.languageSettingsPrivate_.getSpellcheckWords(words => { + this.words_ = words; + }); + + this.languageSettingsPrivate_.onCustomDictionaryChanged.addListener( + this.onCustomDictionaryChanged_.bind(this)); + + // Add a key handler for the new-word input. + this.$.keys.target = this.$.newWord; + }, + + /** + * @return {boolean} + * @private + */ + computeHasWords_() { + return this.words_.length > 0; + }, + + /** + * Adds the word in the new-word input to the dictionary. + * @private + */ + addWordFromInput_() { + // Spaces are allowed, but removing leading and trailing whitespace. + const word = this.getTrimmedNewWord_(); + this.newWordValue_ = ''; + if (word) { + this.languageSettingsPrivate_.addSpellcheckWord(word); + settings.recordSettingChange(); + } + }, + + /** + * @return {string} + * @private + */ + getTrimmedNewWord_() { + return this.newWordValue_.trim(); + }, + + /** + * @return {NewWordState} + * @private + */ + updateNewWordState_() { + const trimmedNewWord = this.getTrimmedNewWord_(); + if (!trimmedNewWord.length) { + return NewWordState.NO_WORD; + } + if (this.words_.includes(trimmedNewWord)) { + return NewWordState.WORD_ALREADY_ADDED; + } + if (new Blob([trimmedNewWord]).size > MAX_CUSTOM_DICTIONARY_WORD_BYTES) { + return NewWordState.WORD_TOO_LONG; + } + return NewWordState.VALID_WORD; + }, + + /** + * @return {boolean} + * @private + */ + shouldDisableAddButton_() { + return this.newWordState_ !== NewWordState.VALID_WORD; + }, + + /** + * @return {string} + * @private + */ + getErrorMessage_() { + switch (this.newWordState_) { + case NewWordState.WORD_TOO_LONG: + return this.i18n('addDictionaryWordLengthError'); + case NewWordState.WORD_ALREADY_ADDED: + return this.i18n('addDictionaryWordDuplicateError'); + default: + return ''; + } + }, + + /** + * @return {boolean} + * @private + */ + isNewWordInvalid_() { + return this.newWordState_ === NewWordState.WORD_TOO_LONG || + this.newWordState_ === NewWordState.WORD_ALREADY_ADDED; + }, + + /** + * Handles tapping on the Add Word button. + * @private + */ + onAddWordTap_() { + this.addWordFromInput_(); + this.$.newWord.focus(); + }, + + /** + * Handles updates to the word list. Additions are unshifted to the top + * of the list so that users can see them easily. + * @param {!Array<string>} added + * @param {!Array<string>} removed + * @private + */ + onCustomDictionaryChanged_(added, removed) { + for (const word of removed) { + this.arrayDelete('words_', word); + } + + for (const word of added) { + if (!this.words_.includes(word)) { + this.unshift('words_', word); + } + } + }, + + /** + * Handles Enter and Escape key presses for the new-word input. + * @param {!CustomEvent<!{key: string}>} e + * @private + */ + onKeysPress_(e) { + if (e.detail.key === 'enter' && !this.disableAddButton_) { + this.addWordFromInput_(); + } else if (e.detail.key === 'esc') { + e.detail.keyboardEvent.target.value = ''; + } + }, + + /** + * Handles tapping on a "Remove word" icon button. + * @param {!{model: !{item: string}}} e + * @private + */ + onRemoveWordTap_(e) { + this.languageSettingsPrivate_.removeSpellcheckWord(e.model.item); + settings.recordSettingChange(); + } +});
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html index 477e4be..860fcfd 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.html
@@ -77,6 +77,10 @@ <div title="[[item.language.nativeDisplayName]]"> [[item.language.displayName]] </div> + <div class="secondary" hidden="[[!isTranslationTarget_( + item.language.code, languages.translateTarget)]]"> + $i18n{translateTargetLabel} + </div> </div> <cr-icon-button class="icon-more-vert" title="$i18n{moreActions}" id="more-[[item.language.code]]"
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js index dc1f183..9796ef5 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page_v2.js
@@ -254,4 +254,15 @@ onTranslateToggleChange_(e) { this.languagesMetricsProxy_.recordToggleTranslate(e.target.checked); }, + + /** + * @param {string} languageCode The language code identifying a language. + * @param {string} translateTarget The target language. + * @return {boolean} true if |languageCode| matches the target language + * @private + */ + isTranslationTarget_(languageCode, translateTarget) { + return this.languageHelper.convertLanguageCodeForTranslate(languageCode) === + translateTarget; + }, });
diff --git a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html index 8843df8..54cf70f4 100644 --- a/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html +++ b/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_section.html
@@ -99,7 +99,8 @@ associated-control="[[$$('#inputPageTrigger')]]" page-title="$i18n{inputPageTitle}"> <os-settings-input-page language-helper="[[languageHelper]]" - languages="[[languages]]" prefs="{{prefs}}"> + languages="[[languages]]" prefs="{{prefs}}" + focus-config="[[focusConfig_]]"> </os-settings-input-page> </settings-subpage> </template> @@ -141,6 +142,15 @@ </settings-input-method-options-page> </settings-subpage> </template> + + <!-- "Customize spell check" sub-sub-page. --> + <template is="dom-if" route-path="/osLanguages/editDictionary"> + <settings-subpage + associated-control="[[$$('#editDictionarySubpageTrigger')]]" + page-title="$i18n{editDictionaryLabel}"> + <os-settings-edit-dictionary-page></os-settings-edit-dictionary-page> + </settings-subpage> + </template> </settings-animated-pages> </template> <script src="os_languages_section.js"></script>
diff --git a/chrome/browser/resources/settings/chromeos/os_route.js b/chrome/browser/resources/settings/chromeos/os_route.js index 4629ecb..92d5e32c 100644 --- a/chrome/browser/resources/settings/chromeos/os_route.js +++ b/chrome/browser/resources/settings/chromeos/os_route.js
@@ -235,6 +235,9 @@ r.OS_LANGUAGES_INPUT_METHOD_OPTIONS = createSubpage( r.OS_LANGUAGES_INPUT, mojom.INPUT_METHOD_OPTIONS_SUBPAGE_PATH, Subpage.kInputMethodOptions); + r.OS_LANGUAGES_EDIT_DICTIONARY = createSubpage( + r.OS_LANGUAGES_INPUT, mojom.EDIT_DICTIONARY_SUBPAGE_PATH, + Subpage.kEditDictionary); } else { r.OS_LANGUAGES_DETAILS = createSubpage( r.OS_LANGUAGES, mojom.LANGUAGES_AND_INPUT_DETAILS_SUBPAGE_PATH,
diff --git a/chrome/browser/resources/settings/chromeos/os_settings.gni b/chrome/browser/resources/settings/chromeos/os_settings.gni index 3026b18a..1f8dfbdd 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings.gni +++ b/chrome/browser/resources/settings/chromeos/os_settings.gni
@@ -46,6 +46,7 @@ "settings.KerberosConfigErrorCode|KerberosConfigErrorCode", "settings.KerberosErrorType|KerberosErrorType", "settings.kMenuCloseDelay|kMenuCloseDelay", + "settings.LanguagesBrowserProxy|LanguagesBrowserProxy", "settings.LanguagesMetricsProxy|LanguagesMetricsProxy", "settings.LanguagesPageInteraction|LanguagesPageInteraction", "settings.MultiDeviceBrowserProxy|MultiDeviceBrowserProxy", @@ -115,6 +116,7 @@ "chrome/browser/resources/settings/chromeos/parental_controls_page/parental_controls_browser_proxy.html|ParentalControlsBrowserProxy,ParentalControlsBrowserProxyImpl", "chrome/browser/resources/settings/chromeos/route_origin_behavior.html|RouteOriginBehaviorImpl,RouteOriginBehavior", "chrome/browser/resources/settings/controls/settings_dropdown_menu.html|DropdownMenuOptionList", + "chrome/browser/resources/settings/languages_page/languages_browser_proxy.html|LanguagesBrowserProxy,LanguagesBrowserProxyImpl", "chrome/browser/resources/settings/lifetime_browser_proxy.html|LifetimeBrowserProxy,LifetimeBrowserProxyImpl", "chrome/browser/resources/settings/people_page/account_manager_browser_proxy.html|AccountManagerBrowserProxy,AccountManagerBrowserProxyImpl,Account", "chrome/browser/resources/settings/people_page/profile_info_browser_proxy.html|ProfileInfoBrowserProxyImpl,ProfileInfoBrowserProxy,ProfileInfo",
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp index fe8efba3..f439edf 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp +++ b/chrome/browser/resources/settings/chromeos/os_settings_resources_v3.grdp
@@ -129,6 +129,11 @@ use_base_dir="false" compress="false" type="BINDATA" /> + <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_EDIT_DICTIONARY_PAGE_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_edit_dictionary_page.m.js" + use_base_dir="false" + compress="false" + type="BINDATA" /> <include name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_PAGE_M_JS" file="${root_gen_dir}/chrome/browser/resources/settings/chromeos/os_languages_page/os_languages_page.m.js" use_base_dir="false" @@ -723,6 +728,11 @@ use_base_dir="false" compress="false" type="BINDATA" /> + <include name="IDR_OS_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_M_JS" + file="${root_gen_dir}/chrome/browser/resources/settings/global_scroll_target_behavior.m.js" + use_base_dir="false" + compress="false" + type="BINDATA" /> <include name="IDR_OS_SETTINGS_I18N_SETUP_JS" file="i18n_setup.js" compress="false"
diff --git a/chrome/browser/resources/settings/chromeos/os_settings_routes.js b/chrome/browser/resources/settings/chromeos/os_settings_routes.js index aba65ab..4b677a6 100644 --- a/chrome/browser/resources/settings/chromeos/os_settings_routes.js +++ b/chrome/browser/resources/settings/chromeos/os_settings_routes.js
@@ -59,6 +59,7 @@ * OS_ACCESSIBILITY: !settings.Route, * OS_LANGUAGES: !settings.Route, * OS_LANGUAGES_DETAILS: !settings.Route, + * OS_LANGUAGES_EDIT_DICTIONARY: !settings.Route, * OS_LANGUAGES_INPUT: !settings.Route, * OS_LANGUAGES_INPUT_METHODS: !settings.Route, * OS_LANGUAGES_INPUT_METHOD_OPTIONS: !settings.Route,
diff --git a/chrome/browser/resources/settings/os_settings_resources.grd b/chrome/browser/resources/settings/os_settings_resources.grd index ec66aa5..687edc0 100644 --- a/chrome/browser/resources/settings/os_settings_resources.grd +++ b/chrome/browser/resources/settings/os_settings_resources.grd
@@ -743,6 +743,12 @@ <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_INPUT_PAGE_JS" file="chromeos/os_languages_page/input_page.js" compress="false" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_EDIT_DICTIONARY_PAGE_HTML" + file="chromeos/os_languages_page/os_edit_dictionary_page.html" + compress="false" type="chrome_html" /> + <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_EDIT_DICTIONARY_PAGE_JS" + file="chromeos/os_languages_page/os_edit_dictionary_page.js" + compress="false" type="chrome_html" /> <structure name="IDR_OS_SETTINGS_LANGUAGES_PAGE_OS_LANGUAGES_PAGE_V2_HTML" file="chromeos/os_languages_page/os_languages_page_v2.html" compress="false" type="chrome_html" />
diff --git a/chrome/browser/sharesheet/drive_share_action.cc b/chrome/browser/sharesheet/drive_share_action.cc index f1495678..018c641 100644 --- a/chrome/browser/sharesheet/drive_share_action.cc +++ b/chrome/browser/sharesheet/drive_share_action.cc
@@ -12,8 +12,10 @@ #include "chrome/browser/ui/browser_navigator.h" #include "chrome/browser/ui/browser_navigator_params.h" #include "components/services/app_service/public/mojom/types.mojom.h" +#include "ui/base/l10n/l10n_util.h" #include "ui/base/page_transition_types.h" #include "ui/base/window_open_disposition.h" +#include "ui/chromeos/strings/grit/ui_chromeos_strings.h" #include "ui/gfx/image/image_skia.h" #include "url/gurl.h" @@ -22,8 +24,7 @@ DriveShareAction::~DriveShareAction() = default; const base::string16 DriveShareAction::GetActionName() { - // TODO(crbug.com/1097623): Get the Action name from files app strings. - return base::UTF8ToUTF16("ShareWithOthers"); + return l10n_util::GetStringUTF16(IDS_FILE_BROWSER_SHARE_BUTTON_LABEL); } const gfx::ImageSkia DriveShareAction::GetActionIcon() {
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index 4f61089..5336e8b 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -1745,6 +1745,8 @@ "app_list/search/drive_quick_access_result.h", "app_list/search/file_chip_result.cc", "app_list/search/file_chip_result.h", + "app_list/search/files/file_result.cc", + "app_list/search/files/file_result.h", "app_list/search/launcher_search/launcher_search_icon_image_loader.cc", "app_list/search/launcher_search/launcher_search_icon_image_loader.h", "app_list/search/launcher_search/launcher_search_icon_image_loader_impl.cc",
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings.grd b/chrome/browser/ui/android/strings/android_chrome_strings.grd index fc0a52b..26f316b 100644 --- a/chrome/browser/ui/android/strings/android_chrome_strings.grd +++ b/chrome/browser/ui/android/strings/android_chrome_strings.grd
@@ -2500,15 +2500,6 @@ </message> <!-- New Tab Page strings --> - <message name="IDS_EXPLORE_OFFLINE_CARD_TITLE" desc="Card title text informing the user that they can explore the offline feed. "> - Keep exploring offline - </message> - <message name="IDS_EXPLORE_OFFLINE_CARD_DESCRIPTION" desc="Card description text informing the user that they can consume the videos, articles and other content even though they are offline. "> - Get articles, videos, and other content from sites you like, even if you’re offline or your connection is poor. - </message> - <message name="IDS_EXPLORE_OFFLINE_CARD_EXPLORE" desc="Button text on the explore offline card on new tab page that shows up when the user is offline. Clicking on this button will take the user to downloads home where they can consume articles, audios and videos while being offline."> - Explore - </message> <message name="IDS_RECENT_TABS" desc="Text for button to show 'Recent tabs', i.e. recently closed tabs and tabs that are open on other devices [CHAR-LIMIT=20]"> Recent tabs </message>
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_DESCRIPTION.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_DESCRIPTION.png.sha1 deleted file mode 100644 index c03bf898..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_DESCRIPTION.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1365dc2ea1c9a1822c0d67b35e9f8e01887c07a5 \ No newline at end of file
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_EXPLORE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_EXPLORE.png.sha1 deleted file mode 100644 index cf9ff110..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_EXPLORE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1365dc2ea1c9a1822c0d67b35e9f8e01887c07a5
diff --git a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_TITLE.png.sha1 b/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_TITLE.png.sha1 deleted file mode 100644 index c03bf898..0000000 --- a/chrome/browser/ui/android/strings/android_chrome_strings_grd/IDS_EXPLORE_OFFLINE_CARD_TITLE.png.sha1 +++ /dev/null
@@ -1 +0,0 @@ -1365dc2ea1c9a1822c0d67b35e9f8e01887c07a5 \ No newline at end of file
diff --git a/chrome/browser/ui/app_list/app_context_menu_unittest.cc b/chrome/browser/ui/app_list/app_context_menu_unittest.cc index b877b67..84a1768 100644 --- a/chrome/browser/ui/app_list/app_context_menu_unittest.cc +++ b/chrome/browser/ui/app_list/app_context_menu_unittest.cc
@@ -11,7 +11,6 @@ #include "ash/public/cpp/app_menu_constants.h" #include "base/bind.h" #include "base/json/json_file_value_serializer.h" -#include "base/macros.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/stringprintf.h" @@ -40,6 +39,7 @@ #include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/testing_profile.h" +#include "chromeos/constants/chromeos_features.h" #include "components/arc/test/fake_app_instance.h" #include "components/keyed_service/core/keyed_service.h" #include "components/services/app_service/public/cpp/app_update.h" @@ -56,19 +56,22 @@ class FakeAppContextMenuDelegate : public app_list::AppContextMenuDelegate { public: FakeAppContextMenuDelegate() = default; + FakeAppContextMenuDelegate(const FakeAppContextMenuDelegate&) = delete; + FakeAppContextMenuDelegate& operator=(const FakeAppContextMenuDelegate&) = + delete; ~FakeAppContextMenuDelegate() override = default; // app_list::AppContextMenuDelegate overrides: void ExecuteLaunchCommand(int event_flags) override {} - - private: - DISALLOW_COPY_AND_ASSIGN(FakeAppContextMenuDelegate); }; class FakeAppListControllerDelegate : public test::TestAppListControllerDelegate { public: FakeAppListControllerDelegate() = default; + FakeAppListControllerDelegate(const FakeAppListControllerDelegate&) = delete; + FakeAppListControllerDelegate& operator=( + const FakeAppListControllerDelegate&) = delete; ~FakeAppListControllerDelegate() override = default; void SetAppPinnable(const std::string& app_id, Pinnable type) { @@ -98,8 +101,6 @@ private: std::map<std::string, Pinnable> pinnable_apps_; std::unordered_set<std::string> open_apps_; - - DISALLOW_COPY_AND_ASSIGN(FakeAppListControllerDelegate); }; std::unique_ptr<KeyedService> MenuManagerFactory( @@ -161,7 +162,8 @@ features::kDesktopPWAsWithoutExtensions); } } - + AppContextMenuTest(const AppContextMenuTest&) = delete; + AppContextMenuTest& operator=(const AppContextMenuTest&) = delete; ~AppContextMenuTest() override = default; void SetUp() override { @@ -346,8 +348,6 @@ std::unique_ptr<FakeAppContextMenuDelegate> menu_delegate_; std::unique_ptr<FakeAppListModelUpdater> model_updater_; apps::AppServiceTest app_service_test_; - - DISALLOW_COPY_AND_ASSIGN(AppContextMenuTest); }; TEST_P(AppContextMenuTest, ExtensionApp) { @@ -673,8 +673,46 @@ } } +// Lacros has its own test suite because the feature needs to be enabled before +// SetUp(). +class AppContextMenuLacrosTest : public AppContextMenuTest { + public: + AppContextMenuLacrosTest() { + feature_list_.InitAndEnableFeature(chromeos::features::kLacrosSupport); + } + AppContextMenuLacrosTest(const AppContextMenuLacrosTest&) = delete; + AppContextMenuLacrosTest& operator=(const AppContextMenuLacrosTest&) = delete; + ~AppContextMenuLacrosTest() override = default; + + private: + base::test::ScopedFeatureList feature_list_; +}; + +TEST_P(AppContextMenuLacrosTest, LacrosApp) { + app_service_test().SetUp(profile()); + app_service_test().FlushMojoCalls(); + + // Create the context menu. + AppServiceContextMenu menu(menu_delegate(), profile(), + extension_misc::kLacrosAppId, controller()); + std::unique_ptr<ui::MenuModel> menu_model = GetMenuModel(&menu); + ASSERT_NE(menu_model, nullptr); + + // Verify expected menu items. + EXPECT_EQ(menu_model->GetItemCount(), 1); + std::vector<MenuState> states; + AddToStates(menu, MenuState(ash::APP_CONTEXT_MENU_NEW_WINDOW), &states); + ValidateMenuState(menu_model.get(), states); +} + INSTANTIATE_TEST_SUITE_P(All, AppContextMenuTest, ::testing::Values(ProviderType::kBookmarkApps, ProviderType::kWebApps), web_app::ProviderTypeParamToString); + +INSTANTIATE_TEST_SUITE_P(All, + AppContextMenuLacrosTest, + ::testing::Values(ProviderType::kBookmarkApps, + ProviderType::kWebApps), + web_app::ProviderTypeParamToString);
diff --git a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc index e67c5457..cb6d669 100644 --- a/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc +++ b/chrome/browser/ui/app_list/app_service/app_service_context_menu.cc
@@ -258,6 +258,7 @@ // Create default items for non-Remote apps. if (app_id() != extension_misc::kChromeAppId && + app_id() != extension_misc::kLacrosAppId && app_type_ != apps::mojom::AppType::kUnknown && app_type_ != apps::mojom::AppType::kRemote) { app_list::AppContextMenu::BuildMenu(menu_model.get());
diff --git a/chrome/browser/ui/app_list/search/files/file_result.cc b/chrome/browser/ui/app_list/search/files/file_result.cc new file mode 100644 index 0000000..cf90088f --- /dev/null +++ b/chrome/browser/ui/app_list/search/files/file_result.cc
@@ -0,0 +1,103 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/app_list/search/files/file_result.h" + +#include <string> +#include <utility> +#include <vector> + +#include "ash/public/cpp/app_list/app_list_types.h" +#include "ash/public/cpp/file_icon_util.h" +#include "base/bind.h" +#include "base/files/file_path.h" +#include "base/i18n/rtl.h" +#include "base/macros.h" +#include "base/no_destructor.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/platform_util.h" +#include "chrome/grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" + +namespace app_list { + +namespace { + +std::string StripHostedFileExtensions(const std::string& filename) { + static const base::NoDestructor<std::vector<std::string>> hosted_extensions( + {".GDOC", ".GSHEET", ".GSLIDES", ".GDRAW", ".GTABLE", ".GLINK", ".GFORM", + ".GMAPS", ".GSITE"}); + + for (const auto& extension : *hosted_extensions) { + if (EndsWith(filename, extension, base::CompareCase::INSENSITIVE_ASCII)) { + return filename.substr(0, filename.size() - extension.size()); + } + } + + return filename; +} + +} // namespace + +FileResult::FileResult(const std::string& schema, + const base::FilePath& filepath, + ResultType result_type, + DisplayType display_type, + float relevance, + Profile* profile) + : filepath_(filepath), profile_(profile) { + DCHECK(profile); + set_id(schema + filepath.value()); + set_relevance(relevance); + + // TODO(crbug.com/1034842): Rename or replace the DriveQuickAccess and + // ZeroStateFile enum values. + + SetResultType(result_type); + switch (result_type) { + case ResultType::kDriveQuickAccess: + SetMetricsType(ash::DRIVE_QUICK_ACCESS); + break; + case ResultType::kZeroStateFile: + SetMetricsType(ash::ZERO_STATE_FILE); + break; + default: + NOTREACHED(); + } + + SetDisplayType(display_type); + switch (display_type) { + case DisplayType::kChip: + SetChipIcon(ash::GetChipIconForPath(filepath)); + break; + case DisplayType::kList: + SetIcon(ash::GetIconForPath(filepath)); + break; + default: + NOTREACHED(); + } + + // Set the details to the display name of the Files app. + base::string16 sanitized_name = base::CollapseWhitespace( + l10n_util::GetStringUTF16(IDS_FILEMANAGER_APP_NAME), true); + base::i18n::SanitizeUserSuppliedString(&sanitized_name); + SetDetails(sanitized_name); + SetTitle(base::UTF8ToUTF16( + StripHostedFileExtensions(filepath.BaseName().value()))); +} + +FileResult::~FileResult() = default; + +void FileResult::Open(int event_flags) { + platform_util::OpenItem(profile_, filepath_, + platform_util::OpenItemType::OPEN_FILE, + platform_util::OpenOperationCallback()); +} + +::std::ostream& operator<<(::std::ostream& os, const FileResult& result) { + return os << "{" << result.title() << ", " << result.relevance() << "}"; +} + +} // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/files/file_result.h b/chrome/browser/ui/app_list/search/files/file_result.h new file mode 100644 index 0000000..7f4a3a45 --- /dev/null +++ b/chrome/browser/ui/app_list/search/files/file_result.h
@@ -0,0 +1,42 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_APP_LIST_SEARCH_FILES_FILE_RESULT_H_ +#define CHROME_BROWSER_UI_APP_LIST_SEARCH_FILES_FILE_RESULT_H_ + +#include <iosfwd> + +#include "base/files/file_path.h" +#include "chrome/browser/ui/app_list/search/chrome_search_result.h" + +class Profile; + +namespace app_list { + +class FileResult : public ChromeSearchResult { + public: + FileResult(const std::string& schema, + const base::FilePath& filepath, + ResultType result_type, + DisplayType display_type, + float relevance, + Profile* profile); + ~FileResult() override; + + FileResult(const FileResult&) = delete; + FileResult& operator=(const FileResult&) = delete; + + // ChromeSearchResult overrides: + void Open(int event_flags) override; + + private: + const base::FilePath filepath_; + Profile* const profile_; +}; + +::std::ostream& operator<<(::std::ostream& os, const FileResult& result); + +} // namespace app_list + +#endif // CHROME_BROWSER_UI_APP_LIST_SEARCH_FILES_FILE_RESULT_H_
diff --git a/chrome/browser/ui/ash/chrome_new_window_client.cc b/chrome/browser/ui/ash/chrome_new_window_client.cc index 95ba31e2..6fbc768 100644 --- a/chrome/browser/ui/ash/chrome_new_window_client.cc +++ b/chrome/browser/ui/ash/chrome_new_window_client.cc
@@ -131,6 +131,8 @@ chromeos::settings::mojom::kLanguagesAndInputSectionPath}, {ChromePage::OSLANGUAGESDETAILS, chromeos::settings::mojom::kLanguagesAndInputDetailsSubpagePath}, + {ChromePage::OSLANGUAGESEDITDICTIONARY, + chromeos::settings::mojom::kEditDictionarySubpagePath}, {ChromePage::OSLANGUAGESINPUT, chromeos::settings::mojom::kInputSubpagePath}, {ChromePage::OSLANGUAGESINPUTMETHODS,
diff --git a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc index 2a0e8a73..231f083b 100644 --- a/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc +++ b/chrome/browser/ui/ash/chrome_new_window_client_browsertest.cc
@@ -294,6 +294,9 @@ base_url.Resolve( chromeos::settings::mojom::kLanguagesAndInputDetailsSubpagePath)); TestOpenChromePage( + ChromePage::OSLANGUAGESEDITDICTIONARY, + base_url.Resolve(chromeos::settings::mojom::kEditDictionarySubpagePath)); + TestOpenChromePage( ChromePage::OSLANGUAGESINPUT, base_url.Resolve(chromeos::settings::mojom::kInputSubpagePath)); TestOpenChromePage(
diff --git a/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc b/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc index a27e5a2..0e38558 100644 --- a/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc +++ b/chrome/browser/ui/ash/launcher/shelf_spinner_controller.cc
@@ -224,7 +224,9 @@ const ash::ShelfID shelf_id(app_id); DCHECK_EQ(it->second.controller(), - owner_->shelf_model()->GetShelfItemDelegate(shelf_id)); + it->second.IsFinished() + ? nullptr + : owner_->shelf_model()->GetShelfItemDelegate(shelf_id)); app_controller_map_.erase(it); return true;
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index 690a433a..435307a0 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -97,6 +97,10 @@ // Enables searching tabs across multiple windows. const base::Feature kTabSearch{"TabSearch", base::FEATURE_DISABLED_BY_DEFAULT}; +// Enables the tab search bubble having a fixed tab strip position. +const base::Feature kTabSearchFixedEntrypoint{ + "TabSearchFixedEntrypoint", base::FEATURE_DISABLED_BY_DEFAULT}; + // Enables showing text next to the 3-dot menu when an update is available. // See https://crbug.com/1001731 const base::Feature kUseTextForUpdateButton{"UseTextForUpdateButton",
diff --git a/chrome/browser/ui/ui_features.h b/chrome/browser/ui/ui_features.h index 2aac982..7cb29c7 100644 --- a/chrome/browser/ui/ui_features.h +++ b/chrome/browser/ui/ui_features.h
@@ -59,6 +59,8 @@ extern const base::Feature kTabSearch; +extern const base::Feature kTabSearchFixedEntrypoint; + extern const base::Feature kUseTextForUpdateButton; extern const base::Feature kWebFooterExperiment;
diff --git a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc index 705690b9..0cad71e 100644 --- a/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc +++ b/chrome/browser/ui/views/plugin_vm/plugin_vm_installer_view_browsertest.cc
@@ -29,6 +29,7 @@ #include "chromeos/tpm/stub_install_attributes.h" #include "components/account_id/account_id.h" #include "components/download/public/background_service/download_metadata.h" +#include "components/download/public/background_service/features.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/user_manager/scoped_user_manager.h" @@ -193,7 +194,10 @@ : public PluginVmInstallerViewBrowserTest { public: PluginVmInstallerViewBrowserTestWithFeatureEnabled() { - feature_list_.InitAndEnableFeature(features::kPluginVm); + feature_list_.InitWithFeaturesAndParameters( + {{features::kPluginVm, {}}, + {download::kDownloadServiceFeature, {{"start_up_delay_ms", "0"}}}}, + {}); } private:
diff --git a/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc b/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc index d80ee7a6..01fb8b9 100644 --- a/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc +++ b/chrome/browser/ui/views/reader_mode/reader_mode_icon_view.cc
@@ -66,17 +66,20 @@ void ReaderModeIconView::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { - if (!navigation_handle->IsInMainFrame()) + content::WebContents* web_contents = GetWebContents(); + if (!navigation_handle->IsInMainFrame() || !web_contents) return; // When navigation is about to happen, ensure timers are appropriately stopped // and reset. UMAHelper::UpdateTimersOnNavigation(GetWebContents(), - GetPageType(GetWebContents())); + GetPageType(web_contents)); } void ReaderModeIconView::DocumentAvailableInMainFrame() { - UMAHelper::StartTimerIfNeeded(GetWebContents(), - GetPageType(GetWebContents())); + content::WebContents* web_contents = GetWebContents(); + if (!web_contents) + return; + UMAHelper::StartTimerIfNeeded(web_contents, GetPageType(web_contents)); } void ReaderModeIconView::UpdateImpl() { @@ -162,16 +165,24 @@ void ReaderModeIconView::OnResult( const dom_distiller::DistillabilityResult& result) { - content::WebContents* contents = GetWebContents(); - if (contents && result.is_last) { - ukm::SourceId source_id = ukm::GetSourceIdForWebContentsDocument(contents); + content::WebContents* web_contents = GetWebContents(); + if (!web_contents) { + Update(); + return; + } + + if (result.is_last) { + ukm::SourceId source_id = + ukm::GetSourceIdForWebContentsDocument(web_contents); ukm::builders::ReaderModeReceivedDistillability(source_id) .SetIsPageDistillable(result.is_distillable) .Record(ukm::UkmRecorder::Get()); } + Update(); + // Once we know the type of page we are on (distillable or not), we can // update the timers. - UMAHelper::ReaderModePageType page_type = GetPageType(contents); - UMAHelper::StartTimerIfNeeded(contents, page_type); + UMAHelper::ReaderModePageType page_type = GetPageType(web_contents); + UMAHelper::StartTimerIfNeeded(web_contents, page_type); }
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc index d262a0d6..5fe71488 100644 --- a/chrome/browser/ui/views/tabs/tab_strip.cc +++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -2177,21 +2177,38 @@ } if (base::FeatureList::IsEnabled(features::kScrollableTabStrip)) { - // With tab scrolling, the tabstrip is solely responsible for its own - // width. - // It should never be larger than its preferred width. - const int max_width = - layout_helper_->CalculatePreferredWidth() + GetRightSideReservedWidth(); - // It should never be smaller than its minimum width. - const int min_width = GetMinimumSize().width(); - // If it can, it should fit within the tab strip region. const int available_width = available_width_callback_.Run(); - // It should be as wide as possible subject to the above constraints. - const int width = std::min(max_width, std::max(min_width, available_width)); - SetBounds(0, 0, width, GetLayoutConstant(TAB_HEIGHT)); + + if (base::FeatureList::IsEnabled(features::kTabSearchFixedEntrypoint)) { + // If the tab search fixed entrypoint is enabled, the tab strip should + // take whole available width. + SetBounds(0, 0, available_width, GetLayoutConstant(TAB_HEIGHT)); + } else { + // With tab scrolling, the tabstrip is solely responsible for its own + // width. + // It should never be larger than its preferred width. + const int max_width = layout_helper_->CalculatePreferredWidth() + + GetRightSideReservedWidth(); + // It should never be smaller than its minimum width. + const int min_width = GetMinimumSize().width(); + // If it can, it should fit within the tab strip region. + // It should be as wide as possible subject to the above constraints. + const int width = + std::min(max_width, std::max(min_width, available_width)); + SetBounds(0, 0, width, GetLayoutConstant(TAB_HEIGHT)); + } + SetTabSlotVisibility(); } + if (tab_search_button_ && + !tab_controls_container_->Contains(tab_search_button_)) { + auto preferred_size = tab_search_button_->GetPreferredSize(); + tab_search_button_->SetBoundsRect( + gfx::Rect(width() - preferred_size.width(), 0, preferred_size.width(), + preferred_size.height())); + } + // Only do a layout if our size changed. if (last_layout_size_ == size() && last_available_width_ != 0) return; @@ -2301,6 +2318,11 @@ // Paint the tab controls. tab_controls_container_->Paint(paint_info); + if (tab_search_button_ && + !tab_controls_container_->Contains(tab_search_button_)) { + tab_search_button_->Paint(paint_info); + } + // If dragging a group, paint the group highlight and header above all // non-dragging tabs and groups. if (dragging_group.has_value()) { @@ -2479,7 +2501,10 @@ tab_search_button->AddObserver(this); tab_search_button_ = - tab_controls_container_->AddChildView(std::move(tab_search_button)); + base::FeatureList::IsEnabled(features::kTabSearchFixedEntrypoint) + ? AddChildView(std::move(tab_search_button)) + : tab_controls_container_->AddChildView( + std::move(tab_search_button)); } UpdateNewTabButtonBorder();
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom b/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom index adefc94..2d64d88 100644 --- a/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom +++ b/chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom
@@ -111,6 +111,7 @@ kInputMethodOptions = 1203, kLanguages = 1204, kInput = 1205, + kEditDictionary = 1206, // Files section. kNetworkFileShares = 1300, @@ -220,6 +221,7 @@ const string kInputMethodOptionsSubpagePath = "osLanguages/inputMethodOptions"; const string kLanguagesSubpagePath = "osLanguages/languages"; const string kInputSubpagePath = "osLanguages/input"; +const string kEditDictionarySubpagePath = "osLanguages/editDictionary"; // Files section. const string kFilesSectionPath = "files";
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc b/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc index c3a8822..dc36534 100644 --- a/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc +++ b/chrome/browser/ui/webui/settings/chromeos/constants/routes_util.cc
@@ -98,6 +98,7 @@ chromeos::settings::mojom::kInputMethodOptionsSubpagePath, chromeos::settings::mojom::kLanguagesSubpagePath, chromeos::settings::mojom::kInputSubpagePath, + chromeos::settings::mojom::kEditDictionarySubpagePath, // Files section. chromeos::settings::mojom::kFilesSectionPath,
diff --git a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc index 294774e..125d03b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/languages_section.cc +++ b/chrome/browser/ui/webui/settings/chromeos/languages_section.cc
@@ -17,6 +17,7 @@ #include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_pref_names.h" #include "components/prefs/pref_service.h" +#include "components/spellcheck/browser/pref_names.h" #include "content/public/browser/web_ui_data_source.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/webui/web_ui_util.h" @@ -119,6 +120,18 @@ return *tags; } +const std::vector<SearchConcept>& GetEditDictionarySearchConceptsV2() { + static const base::NoDestructor<std::vector<SearchConcept>> tags({ + {IDS_OS_SETTINGS_TAG_LANGUAGES_EDIT_DICTIONARY, + mojom::kEditDictionarySubpagePath, + mojom::SearchResultIcon::kGlobe, + mojom::SearchResultDefaultRank::kMedium, + mojom::SearchResultType::kSubpage, + {.subpage = mojom::Subpage::kEditDictionary}}, + }); + return *tags; +} + bool IsLanguageSettingsV2Enabled() { return base::FeatureList::IsEnabled( ::chromeos::features::kLanguageSettingsUpdate); @@ -257,6 +270,8 @@ IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PREFERENCE_TITLE}, {"languagesPreferenceDescription", IDS_OS_SETTINGS_LANGUAGES_LANGUAGES_PREFERENCE_DESCRIPTION}, + {"translateTargetLabel", + IDS_OS_SETTINGS_LANGUAGES_TRANSLATE_TARGET_LABEL}, {"offerTranslationLabel", IDS_OS_SETTINGS_LANGUAGES_OFFER_TRANSLATION_LABEL}, {"offerTranslationSublabel", @@ -302,6 +317,18 @@ {"languagesDictionaryDownloadRetryDescription", IDS_OS_SETTINGS_LANGUAGES_DICTIONARY_DOWNLOAD_RETRY_DESCRIPTION}, {"editDictionaryLabel", IDS_OS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_LABEL}, + {"editDictionaryDescription", + IDS_OS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_DESCRIPTION}, + {"addDictionaryWordButtonLabel", + IDS_OS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_BUTTON_LABEL}, + {"addDictionaryWordDuplicateError", + IDS_OS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_DUPLICATE_ERROR}, + {"addDictionaryWordLengthError", + IDS_OS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD_LENGTH_ERROR}, + {"deleteDictionaryWordTooltip", + IDS_OS_SETTINGS_LANGUAGES_DELETE_DICTIONARY_WORD_TOOLTIP}, + {"noDictionaryWordsLabel", + IDS_OS_SETTINGS_LANGUAGES_NO_DICTIONARY_WORDS_LABEL}, }; AddLocalizedStringsBulk(html_source, kLocalizedStrings); } @@ -309,12 +336,21 @@ } // namespace LanguagesSection::LanguagesSection(Profile* profile, - SearchTagRegistry* search_tag_registry) - : OsSettingsSection(profile, search_tag_registry) { + SearchTagRegistry* search_tag_registry, + PrefService* pref_service) + : OsSettingsSection(profile, search_tag_registry), + pref_service_(pref_service) { SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); if (IsLanguageSettingsV2Enabled()) { + pref_change_registrar_.Init(pref_service_); + pref_change_registrar_.Add( + spellcheck::prefs::kSpellCheckEnable, + base::BindRepeating(&LanguagesSection::UpdateSpellCheckSearchTags, + base::Unretained(this))); + updater.AddSearchTags(GetLanguagesPageSearchConceptsV2()); updater.AddSearchTags(GetInputPageSearchConceptsV2()); + UpdateSpellCheckSearchTags(); } else { updater.AddSearchTags(GetLanguagesSearchConceptsV1()); } @@ -402,13 +438,6 @@ return mojom::kLanguagesAndInputSectionPath; } -bool LanguagesSection::IsEmojiSuggestionAllowed() const { - return base::FeatureList::IsEnabled( - ::chromeos::features::kEmojiSuggestAddition) && - profile()->GetPrefs()->GetBoolean( - ::chromeos::prefs::kEmojiSuggestionEnterpriseAllowed); -} - void LanguagesSection::RegisterHierarchy(HierarchyGenerator* generator) const { // Languages. generator->RegisterTopLevelSubpage( @@ -434,6 +463,13 @@ RegisterNestedSettingBulk(mojom::Subpage::kInput, kInputPageSettings, generator); + // Edit dictionary. + generator->RegisterNestedSubpage( + IDS_OS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_LABEL, + mojom::Subpage::kEditDictionary, mojom::Subpage::kInput, + mojom::SearchResultIcon::kGlobe, mojom::SearchResultDefaultRank::kMedium, + mojom::kEditDictionarySubpagePath); + // Languages and input details. generator->RegisterTopLevelSubpage( IDS_OS_SETTINGS_LANGUAGES_AND_INPUT_PAGE_TITLE, @@ -494,5 +530,24 @@ kSmartInputsFeaturesSettings, generator); } +bool LanguagesSection::IsEmojiSuggestionAllowed() const { + return base::FeatureList::IsEnabled( + ::chromeos::features::kEmojiSuggestAddition) && + pref_service_->GetBoolean( + ::chromeos::prefs::kEmojiSuggestionEnterpriseAllowed); +} + +bool LanguagesSection::IsSpellCheckEnabled() const { + return pref_service_->GetBoolean(spellcheck::prefs::kSpellCheckEnable); +} + +void LanguagesSection::UpdateSpellCheckSearchTags() { + SearchTagRegistry::ScopedTagUpdater updater = registry()->StartUpdate(); + updater.RemoveSearchTags(GetEditDictionarySearchConceptsV2()); + if (IsSpellCheckEnabled()) { + updater.AddSearchTags(GetEditDictionarySearchConceptsV2()); + } +} + } // namespace settings } // namespace chromeos
diff --git a/chrome/browser/ui/webui/settings/chromeos/languages_section.h b/chrome/browser/ui/webui/settings/chromeos/languages_section.h index 92364557..6faa782b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/languages_section.h +++ b/chrome/browser/ui/webui/settings/chromeos/languages_section.h
@@ -6,6 +6,7 @@ #define CHROME_BROWSER_UI_WEBUI_SETTINGS_CHROMEOS_LANGUAGES_SECTION_H_ #include "chrome/browser/ui/webui/settings/chromeos/os_settings_section.h" +#include "components/prefs/pref_change_registrar.h" namespace content { class WebUIDataSource; @@ -21,7 +22,9 @@ // the relevant features are enabled. class LanguagesSection : public OsSettingsSection { public: - LanguagesSection(Profile* profile, SearchTagRegistry* search_tag_registry); + LanguagesSection(Profile* profile, + SearchTagRegistry* search_tag_registry, + PrefService* pref_service); ~LanguagesSection() override; private: @@ -35,6 +38,11 @@ void RegisterHierarchy(HierarchyGenerator* generator) const override; bool IsEmojiSuggestionAllowed() const; + bool IsSpellCheckEnabled() const; + void UpdateSpellCheckSearchTags(); + + PrefService* pref_service_; + PrefChangeRegistrar pref_change_registrar_; }; } // namespace settings
diff --git a/chrome/browser/ui/webui/settings/chromeos/os_settings_sections.cc b/chrome/browser/ui/webui/settings/chromeos/os_settings_sections.cc index 744325a..0f2b11b 100644 --- a/chrome/browser/ui/webui/settings/chromeos/os_settings_sections.cc +++ b/chrome/browser/ui/webui/settings/chromeos/os_settings_sections.cc
@@ -103,8 +103,8 @@ sections_map_[mojom::Section::kPrivacyAndSecurity] = privacy_section.get(); sections_.push_back(std::move(privacy_section)); - auto language_section = - std::make_unique<LanguagesSection>(profile, search_tag_registry); + auto language_section = std::make_unique<LanguagesSection>( + profile, search_tag_registry, profile->GetPrefs()); sections_map_[mojom::Section::kLanguagesAndInput] = language_section.get(); sections_.push_back(std::move(language_section));
diff --git a/chrome/browser/web_applications/components/external_app_install_features.cc b/chrome/browser/web_applications/components/external_app_install_features.cc index 027f934..7592179 100644 --- a/chrome/browser/web_applications/components/external_app_install_features.cc +++ b/chrome/browser/web_applications/components/external_app_install_features.cc
@@ -10,31 +10,37 @@ namespace { -// A hard coded list of features available for externally installed apps to gate -// their installation on via their config file settings. -constexpr base::Feature kExternalAppInstallFeatures[] = { - // Enables migration of default installed GSuite apps over to their - // replacement web apps. - {"MigrateDefaultChromeAppToWebAppsGSuite", - base::FEATURE_DISABLED_BY_DEFAULT}, - - // Enables migration of default installed non-GSuite apps over to their - // replacement web apps. - {"MigrateDefaultChromeAppToWebAppsNonGSuite", - base::FEATURE_DISABLED_BY_DEFAULT}, +// A hard coded list of features available for externally installed apps to +// gate their installation on via their config file settings. See +// |kFeatureName| in external_web_app_utils.h. +constexpr const base::Feature* kExternalAppInstallFeatures[] = { + &kMigrateDefaultChromeAppToWebAppsGSuite, + &kMigrateDefaultChromeAppToWebAppsNonGSuite, }; bool g_always_enabled_for_testing = false; } // namespace +// Enables migration of default installed GSuite apps over to their replacement +// web apps. +const base::Feature kMigrateDefaultChromeAppToWebAppsGSuite{ + "MigrateDefaultChromeAppToWebAppsGSuite", + base::FEATURE_DISABLED_BY_DEFAULT}; + +// Enables migration of default installed non-GSuite apps over to their +// replacement web apps. +const base::Feature kMigrateDefaultChromeAppToWebAppsNonGSuite{ + "MigrateDefaultChromeAppToWebAppsNonGSuite", + base::FEATURE_DISABLED_BY_DEFAULT}; + bool IsExternalAppInstallFeatureEnabled(base::StringPiece feature_name) { if (g_always_enabled_for_testing) return true; - for (const base::Feature& feature : kExternalAppInstallFeatures) { - if (feature.name == feature_name) - return base::FeatureList::IsEnabled(feature); + for (const base::Feature* feature : kExternalAppInstallFeatures) { + if (feature->name == feature_name) + return base::FeatureList::IsEnabled(*feature); } return false;
diff --git a/chrome/browser/web_applications/components/external_app_install_features.h b/chrome/browser/web_applications/components/external_app_install_features.h index 2a6c1e5..32eed21ca 100644 --- a/chrome/browser/web_applications/components/external_app_install_features.h +++ b/chrome/browser/web_applications/components/external_app_install_features.h
@@ -6,14 +6,15 @@ #define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_EXTERNAL_APP_INSTALL_FEATURES_H_ #include "base/auto_reset.h" +#include "base/feature_list.h" #include "base/strings/string_piece_forward.h" -namespace base { -struct Feature; -} - namespace web_app { +extern const base::Feature kMigrateDefaultChromeAppToWebAppsGSuite; + +extern const base::Feature kMigrateDefaultChromeAppToWebAppsNonGSuite; + // Returns the base::Feature in |kExternalAppInstallFeatures| that corresponds // to |feature_name|. Used by external app install configs to gate installation // on features listed in |kExternalAppInstallFeatures|.
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt index ef1da766..7096898 100644 --- a/chrome/build/linux.pgo.txt +++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@ -chrome-linux-master-1599911279-ab348b4db9373a96976d429b879787886667adea.profdata +chrome-linux-master-1600062449-3179a4da9bad3e513a066b6120519028fcbec2a4.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt index 3e22bf4..e3d9418 100644 --- a/chrome/build/mac.pgo.txt +++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@ -chrome-mac-master-1599911279-d8e721e2ccdf8b7ee333abd0f496ddac0b6f8dcd.profdata +chrome-mac-master-1600062449-eb397872f2f81f98b45c4ec794b206b9a087897d.profdata
diff --git a/chrome/build/win32.pgo.txt b/chrome/build/win32.pgo.txt index e92ff4b..0b1d021 100644 --- a/chrome/build/win32.pgo.txt +++ b/chrome/build/win32.pgo.txt
@@ -1 +1 @@ -chrome-win32-master-1599911279-1c781834ab61239127a33b9dd2cde48636a47a86.profdata +chrome-win32-master-1600019602-32c2a84e23bf8e92bb08ca2c2b541f0b03d0321b.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt index c9126ac..35132db 100644 --- a/chrome/build/win64.pgo.txt +++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@ -chrome-win64-master-1599890263-b59c60595b9597a822ba1a0876e8b00dac62f9f3.profdata +chrome-win64-master-1600041484-a30af8f2a2acd0d94a4d04ce1984e089b193fca0.profdata
diff --git a/chrome/common/extensions/api/file_manager_private.idl b/chrome/common/extensions/api/file_manager_private.idl index 4990eb6..be525ee 100644 --- a/chrome/common/extensions/api/file_manager_private.idl +++ b/chrome/common/extensions/api/file_manager_private.idl
@@ -152,10 +152,12 @@ // Result of task execution. If changing, update the strings used in // ui/file_manager/file_manager/foreground/js/file_tasks.js enum TaskResult { - // The task execution succeeded and a new window/tab was opened. + // The task execution succeeded and a new window/tab was opened on the current + // desktop. opened, // The task execution succeeded and the message was sent to the proper - // extension. + // extension or app. This could result in a window being opened on a different + // desktop. message_sent, // The task execution failed. failed, @@ -640,6 +642,9 @@ // Whether the device has a cellular network access or not. i.e. the |type| // can be 'metered' or not. boolean hasCellularNetworkAccess; + + // Whether or not hosted files can be pinned. + boolean canPinHostedFiles; }; // Device event dispatched to listeners of onDeviceChaged. See also
diff --git a/chrome/test/chromedriver/chrome/device_manager_unittest.cc b/chrome/test/chromedriver/chrome/device_manager_unittest.cc index 02fab53..5495382 100644 --- a/chrome/test/chromedriver/chrome/device_manager_unittest.cc +++ b/chrome/test/chromedriver/chrome/device_manager_unittest.cc
@@ -156,7 +156,7 @@ } TEST(Device, StartStopApp) { - int devtools_port; + int devtools_port = 0; FakeAdb adb; DeviceManager device_manager(&adb); std::unique_ptr<Device> device1;
diff --git a/chrome/test/data/extensions/api_test/file_browser/open_gallery/test.js b/chrome/test/data/extensions/api_test/file_browser/open_gallery/test.js index 8b2905d5..0f73e51b 100644 --- a/chrome/test/data/extensions/api_test/file_browser/open_gallery/test.js +++ b/chrome/test/data/extensions/api_test/file_browser/open_gallery/test.js
@@ -36,20 +36,31 @@ * A method the camera app uses to open its "camera roll". Instrumented for * testing. See chromeos/camera/src/js/browser_proxy/browser_proxy.js. */ -function openGallery(entry) { +function openGallery(entry, expectedResult) { // "jhdjimmaggjajfjphpljagpgkidjilnj" is the MediaApp app id. This task id is // hard-coded in the Camera component app. const id = 'jhdjimmaggjajfjphpljagpgkidjilnj|web|open'; function taskCallback(taskResult) { - chrome.test.assertEq( - chrome.fileManagerPrivate.TaskResult.MESSAGE_SENT, taskResult); + chrome.test.assertEq(expectedResult, taskResult); chrome.test.succeed(); } chrome.fileManagerPrivate.executeTask(id, [entry], taskCallback); } -function testPngOpensGallery() { - getFileEntry('testing', kTestPng).then(openGallery); +function openGalleryExpectOpened(entry) { + openGallery(entry, chrome.fileManagerPrivate.TaskResult.OPENED); +} + +function openGalleryExpectMsgSent(entry) { + openGallery(entry, chrome.fileManagerPrivate.TaskResult.MESSAGE_SENT); +} + +function testPngOpensGalleryReturnsOpened() { + getFileEntry('testing', kTestPng).then(openGalleryExpectOpened); +} + +function testPngOpensGalleryReturnsMsgSent() { + getFileEntry('testing', kTestPng).then(openGalleryExpectMsgSent); } // Handle the case where JSTestStarter has already injected a test to run.
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index 01cff916..dc99aab5 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -288,6 +288,7 @@ "$root_gen_dir/chrome/test/data/webui/settings/chromeos/multidevice_subpage_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/nearby_share_receive_dialog_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/nearby_share_subpage_tests.m.js", + "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_edit_dictionary_page_test.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_languages_page_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.m.js", "$root_gen_dir/chrome/test/data/webui/settings/chromeos/os_reset_page_test.m.js",
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js index 6468d01..c1e9f6b3 100644 --- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js +++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -519,9 +519,10 @@ extension_manager_tests.TestNames.UrlNavigationToDetails); }); +// Disabled as flaky. TODO(crbug.com/1127741): Enable this test. TEST_F( - 'CrExtensionsManagerTestWithIdQueryParam', 'UrlNavigationToActivityLogFail', - function() { + 'CrExtensionsManagerTestWithIdQueryParam', + 'DISABLED_UrlNavigationToActivityLogFail', function() { this.runMochaTest( extension_manager_tests.TestNames.UrlNavigationToActivityLogFail); });
diff --git a/chrome/test/data/webui/settings/chromeos/BUILD.gn b/chrome/test/data/webui/settings/chromeos/BUILD.gn index 9b3f769e..77564f5e 100644 --- a/chrome/test/data/webui/settings/chromeos/BUILD.gn +++ b/chrome/test/data/webui/settings/chromeos/BUILD.gn
@@ -50,6 +50,7 @@ "multidevice_subpage_tests.js", "nearby_share_receive_dialog_tests.js", "nearby_share_subpage_tests.js", + "os_edit_dictionary_page_test.js", "os_languages_page_tests.js", "os_languages_page_v2_tests.js", "os_reset_page_test.js",
diff --git a/chrome/test/data/webui/settings/chromeos/input_page_test.js b/chrome/test/data/webui/settings/chromeos/input_page_test.js index c1f9b48e..dae5bb5d 100644 --- a/chrome/test/data/webui/settings/chromeos/input_page_test.js +++ b/chrome/test/data/webui/settings/chromeos/input_page_test.js
@@ -459,5 +459,15 @@ assertTrue(editDictionarySubpageTrigger.disabled); }); + + test('opens edit dictionary page', () => { + const editDictionarySubpageTrigger = + inputPage.$$('#editDictionarySubpageTrigger'); + editDictionarySubpageTrigger.click(); + const router = settings.Router.getInstance(); + assertEquals( + router.getCurrentRoute().getAbsolutePath(), + 'chrome://os-settings/osLanguages/editDictionary'); + }); }); });
diff --git a/chrome/test/data/webui/settings/chromeos/os_edit_dictionary_page_test.js b/chrome/test/data/webui/settings/chromeos/os_edit_dictionary_page_test.js new file mode 100644 index 0000000..64bac97 --- /dev/null +++ b/chrome/test/data/webui/settings/chromeos/os_edit_dictionary_page_test.js
@@ -0,0 +1,256 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// clang-format off +// #import {LanguagesBrowserProxyImpl} from 'chrome://os-settings/chromeos/lazy_load.js'; +// #import {CrSettingsPrefs} from 'chrome://os-settings/chromeos/os_settings.js'; +// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; +// #import {FakeLanguageSettingsPrivate} from '../fake_language_settings_private.m.js'; +// #import {FakeSettingsPrivate} from '../fake_settings_private.m.js'; +// #import {TestLanguagesBrowserProxy} from './test_os_languages_browser_proxy.m.js'; +// clang-format on + +suite('edit dictionary page', () => { + function getFakePrefs() { + return [ + { + key: 'intl.app_locale', + type: chrome.settingsPrivate.PrefType.STRING, + value: 'en-US', + }, + { + key: 'intl.accept_languages', + type: chrome.settingsPrivate.PrefType.STRING, + value: 'en-US,sw', + }, + { + key: 'spellcheck.dictionaries', + type: chrome.settingsPrivate.PrefType.LIST, + value: ['en-US'], + }, + { + key: 'translate_blocked_languages', + type: chrome.settingsPrivate.PrefType.LIST, + value: ['en-US'], + }, + { + key: 'settings.language.preferred_languages', + type: chrome.settingsPrivate.PrefType.STRING, + value: 'en-US,sw', + }, + { + key: 'settings.language.preload_engines', + type: chrome.settingsPrivate.PrefType.STRING, + value: '_comp_ime_fgoepimhcoialccpbmpnnblemnepkkaoxkb:us::eng,' + + '_comp_ime_fgoepimhcoialccpbmpnnblemnepkkaoxkb:us:dvorak:eng', + }, + { + key: 'settings.language.enabled_extension_imes', + type: chrome.settingsPrivate.PrefType.STRING, + value: '', + }, + ]; + } + + /** @type {?settings.SettingsEditDictionaryPageElement} */ + let editDictPage; + /** @type {?settings.FakeLanguageSettingsPrivate} */ + let languageSettingsPrivate; + /** @type {?settings.FakeSettingsPrivate} */ + let settingsPrefs; + + suiteSetup(() => { + CrSettingsPrefs.deferInitialization = true; + loadTimeData.overrideValues({enableLanguageSettingsV2: true}); + }); + + setup(() => { + document.body.innerHTML = ''; + settingsPrefs = document.createElement('settings-prefs'); + const settingsPrivate = new settings.FakeSettingsPrivate(getFakePrefs()); + settingsPrefs.initialize(settingsPrivate); + + languageSettingsPrivate = new settings.FakeLanguageSettingsPrivate(); + languageSettingsPrivate.setSettingsPrefs(settingsPrefs); + const browserProxy = new settings.TestLanguagesBrowserProxy(); + settings.LanguagesBrowserProxyImpl.instance_ = browserProxy; + browserProxy.setLanguageSettingsPrivate(languageSettingsPrivate); + + editDictPage = document.createElement('os-settings-edit-dictionary-page'); + + // Prefs would normally be data-bound to settings-languages. + document.body.appendChild(editDictPage); + }); + + test('adds word validation', () => { + // Check addWord enable/disable logic + const addWordButton = editDictPage.$.addWord; + assertTrue(!!addWordButton); + editDictPage.$.newWord.value = ''; + assertTrue(addWordButton.disabled); + editDictPage.$.newWord.value = 'valid word'; + assertFalse(addWordButton.disabled); + assertFalse( + window.getComputedStyle(addWordButton)['pointer-events'] === + 'none'); // Make sure add-word button actually clickable. + }); + + test('shows error when adding duplicate word', () => { + const WORD = 'unique'; + loadTimeData.overrideValues({ + addDictionaryWordDuplicateError: 'duplicate', + }); + // add word + languageSettingsPrivate.onCustomDictionaryChanged.callListeners([WORD], []); + editDictPage.$.newWord.value = `${WORD} ${WORD}`; + Polymer.dom.flush(); + assertFalse(editDictPage.$.addWord.disabled); + assertFalse(editDictPage.$.newWord.invalid); + assertEquals(editDictPage.$.newWord.errorMessage, ''); + + // add duplicate word + editDictPage.$.newWord.value = WORD; + Polymer.dom.flush(); + assertTrue(editDictPage.$.addWord.disabled); + assertTrue(editDictPage.$.newWord.invalid); + assertEquals(editDictPage.$.newWord.errorMessage, 'duplicate'); + + // remove word + languageSettingsPrivate.onCustomDictionaryChanged.callListeners([], [WORD]); + Polymer.dom.flush(); + assertFalse(editDictPage.$.addWord.disabled); + assertFalse(editDictPage.$.newWord.invalid); + assertEquals(editDictPage.$.newWord.errorMessage, ''); + }); + + test('shows error when adding word bigger than 99 bytes', () => { + const OK_WORD = 'u'.repeat(99); + const TOO_LONG_WORD = 'u'.repeat(100); + // This emoji has length 2 and bytesize 4. + const TOO_BIG_WORD = '😎'.repeat(25); + loadTimeData.overrideValues({ + addDictionaryWordLengthError: 'too long', + }); + + editDictPage.$.newWord.value = OK_WORD; + Polymer.dom.flush(); + + assertFalse(editDictPage.$.addWord.disabled); + assertFalse(editDictPage.$.newWord.invalid); + assertEquals(editDictPage.$.newWord.errorMessage, ''); + + editDictPage.$.newWord.value = TOO_LONG_WORD; + Polymer.dom.flush(); + + assertTrue(editDictPage.$.addWord.disabled); + assertTrue(editDictPage.$.newWord.invalid); + assertEquals(editDictPage.$.newWord.errorMessage, 'too long'); + + editDictPage.$.newWord.value = TOO_BIG_WORD; + Polymer.dom.flush(); + + assertTrue(editDictPage.$.addWord.disabled); + assertTrue(editDictPage.$.newWord.invalid); + assertEquals(editDictPage.$.newWord.errorMessage, 'too long'); + }); + + test('shows message when empty', () => { + assertTrue(!!editDictPage); + return languageSettingsPrivate.whenCalled('getSpellcheckWords').then(() => { + Polymer.dom.flush(); + + assertFalse(editDictPage.$.noWordsLabel.hidden); + }); + }); + + test('adds words', () => { + const addWordButton = editDictPage.$$('#addWord'); + editDictPage.$.newWord.value = 'valid word'; + addWordButton.click(); + editDictPage.$.newWord.value = 'valid word2'; + addWordButton.click(); + Polymer.dom.flush(); + + assertTrue(editDictPage.$.noWordsLabel.hidden); + assertTrue(!!editDictPage.$$('#list')); + const listItems = editDictPage.$$('#list').items; + assertEquals(2, listItems.length); + // list is shown with latest word added on top. + assertEquals('valid word2', listItems[0]); + assertEquals('valid word', listItems[1]); + }); + + test('removes word', () => { + const addWordButton = editDictPage.$$('#addWord'); + editDictPage.$.newWord.value = 'valid word'; + addWordButton.click(); + Polymer.dom.flush(); + + assertTrue(!!editDictPage.$$('#list')); + assertEquals(1, editDictPage.$$('#list').items.length); + + const removeWordButton = editDictPage.$$('cr-icon-button'); + removeWordButton.click(); + Polymer.dom.flush(); + + assertFalse(editDictPage.$.noWordsLabel.hidden); + assertTrue(!!editDictPage.$$('#list')); + assertEquals(0, editDictPage.$$('#list').items.length); + }); + + test('syncs removed and added words', () => { + languageSettingsPrivate.onCustomDictionaryChanged.callListeners( + /*added=*/['word1', 'word2', 'word3'], /*removed=*/[]); + Polymer.dom.flush(); + + assertTrue(!!editDictPage.$$('#list')); + let listItems = editDictPage.$$('#list').items; + assertEquals(3, listItems.length); + // list is shown with latest word added on top. + assertEquals('word3', listItems[0]); + assertEquals('word2', listItems[1]); + assertEquals('word1', listItems[2]); + + languageSettingsPrivate.onCustomDictionaryChanged.callListeners( + /*added=*/['word4'], /*removed=*/['word2', 'word3']); + Polymer.dom.flush(); + + assertTrue(!!editDictPage.$$('#list')); + listItems = editDictPage.$$('#list').items; + assertEquals(2, listItems.length); + // list is shown with latest word added on top. + assertEquals('word4', listItems[0]); + assertEquals('word1', listItems[1]); + }); + + test('removes is in tab order', () => { + const addWordButton = editDictPage.$$('#addWord'); + editDictPage.$.newWord.value = 'valid word'; + addWordButton.click(); + Polymer.dom.flush(); + + assertTrue(editDictPage.$.noWordsLabel.hidden); + assertTrue(!!editDictPage.$$('#list')); + assertEquals(1, editDictPage.$$('#list').items.length); + + const removeWordButton = editDictPage.$$('cr-icon-button'); + // Button should be reachable in the tab order. + assertEquals('0', removeWordButton.getAttribute('tabindex')); + removeWordButton.click(); + Polymer.dom.flush(); + + assertFalse(editDictPage.$.noWordsLabel.hidden); + + editDictPage.$.newWord.value = 'valid word2'; + addWordButton.click(); + Polymer.dom.flush(); + + assertTrue(editDictPage.$.noWordsLabel.hidden); + assertTrue(!!editDictPage.$$('#list')); + assertEquals(1, editDictPage.$$('#list').items.length); + const newRemoveWordButton = editDictPage.$$('cr-icon-button'); + // Button should be reachable in the tab order. + assertEquals('0', newRemoveWordButton.getAttribute('tabindex')); + }); +});
diff --git a/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js b/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js index 16e9431..766185f1 100644 --- a/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js +++ b/chrome/test/data/webui/settings/chromeos/os_languages_page_v2_tests.js
@@ -224,6 +224,43 @@ actionMenu.close(); }); + test('test translate target language is labelled', function() { + // Translate target language disabled. + const targetLanguageCode = languageHelper.languages.translateTarget; + assertTrue(!!targetLanguageCode); + assertTrue(languageHelper.languages.enabled.some( + l => languageHelper.convertLanguageCodeForTranslate( + l.language.code) === targetLanguageCode)); + assertTrue(languageHelper.languages.enabled.some( + l => languageHelper.convertLanguageCodeForTranslate( + l.language.code) !== targetLanguageCode)); + let translateTargetLabel = null; + let item = null; + + const listItems = languagesList.querySelectorAll('.list-item'); + const domRepeat = languagesList.querySelector('dom-repeat'); + assertTrue(!!domRepeat); + + let num_visibles = 0; + Array.from(listItems).forEach(function(el) { + item = domRepeat.itemForElement(el); + if (item) { + translateTargetLabel = el.querySelector('.secondary'); + assertTrue(!!translateTargetLabel); + if (getComputedStyle(translateTargetLabel).display !== 'none') { + num_visibles++; + assertEquals( + targetLanguageCode, + languageHelper.convertLanguageCodeForTranslate( + item.language.code)); + } + } + assertEquals( + 1, num_visibles, + 'Not exactly one target info label (' + num_visibles + ').'); + }); + }); + test('Deep link to add language', async () => { loadTimeData.overrideValues({ isDeepLinkingEnabled: true,
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js index 58d0bdd..78ffc92 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_browsertest.js
@@ -1731,6 +1731,32 @@ } }; +// eslint-disable-next-line no-var +var OSSettingsEditDictionaryPageTest = class extends OSSettingsBrowserTest { + /** @override */ + get browsePreload() { + return super.browsePreload + + 'chromeos/os_language_page/os_edit_dictionary_page.html'; + } + + /** @override */ + get extraLibraries() { + return super.extraLibraries.concat([ + BROWSER_SETTINGS_PATH + '../fake_chrome_event.js', + BROWSER_SETTINGS_PATH + '../test_browser_proxy.js', + BROWSER_SETTINGS_PATH + 'fake_input_method_private.js', + BROWSER_SETTINGS_PATH + 'fake_language_settings_private.js', + BROWSER_SETTINGS_PATH + 'fake_settings_private.js', + 'os_edit_dictionary_page_test.js', + 'test_os_languages_browser_proxy.js', + ]); + } +}; + +TEST_F('OSSettingsEditDictionaryPageTest', 'AllJsTests', () => { + mocha.run(); +}); + TEST_F('OSSettingsResetPageTest', 'AllJsTests', () => { mocha.run(); });
diff --git a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js index 5c1caac0b..ea70ea0 100644 --- a/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/chromeos/os_settings_v3_browsertest.js
@@ -82,6 +82,7 @@ ['MultidevicePage', 'multidevice_page_tests.m.js'], ['MultideviceSmartLockSubPage', 'multidevice_smartlock_subpage_test.m.js'], ['MultideviceSubPage', 'multidevice_subpage_tests.m.js'], + ['OsEditDictionaryPage', 'os_edit_dictionary_page_test.m.js'], ['OsLanguagesPage', 'os_languages_page_tests.m.js'], ['NearbyShareReceiveDialog', 'nearby_share_receive_dialog_tests.m.js'], ['NearbyShareSubPage', 'nearby_share_subpage_tests.m.js'],
diff --git a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js index d350758..a7829ca 100644 --- a/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_v3_browsertest.js
@@ -510,7 +510,8 @@ ['PrefUtil', 'pref_util_tests.m.js'], ['ProtocolHandlers', 'protocol_handlers_tests.js'], ['RecentSitePermissions', 'recent_site_permissions_test.js'], - ['ResetPage', 'reset_page_test.js'], + // Flaky on all OSes. TODO(crbug.com/1127733): Enable the test. + ['ResetPage', 'reset_page_test.js', 'DISABLED_All'], ['ResetProfileBanner', 'reset_profile_banner_test.js'], ['SearchEngines', 'search_engines_page_test.js'], ['SearchPage', 'search_page_test.js'],
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 744c874..3d15f9d 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -13464.0.0 \ No newline at end of file +13466.0.0 \ No newline at end of file
diff --git a/components/arc/mojom/intent_helper.mojom b/components/arc/mojom/intent_helper.mojom index b3cde37..15a2920 100644 --- a/components/arc/mojom/intent_helper.mojom +++ b/components/arc/mojom/intent_helper.mojom
@@ -196,8 +196,9 @@ DEPRECATED_DOWNLOADEDCONTENT, OSLANGUAGESINPUT, OSLANGUAGESLANGUAGES, + OSLANGUAGESEDITDICTIONARY, - LAST = OSLANGUAGESLANGUAGES + LAST = OSLANGUAGESEDITDICTIONARY }; // Describes an unique chrome app.
diff --git a/components/autofill_assistant/browser/BUILD.gn b/components/autofill_assistant/browser/BUILD.gn index 65facbe..fb07fa29 100644 --- a/components/autofill_assistant/browser/BUILD.gn +++ b/components/autofill_assistant/browser/BUILD.gn
@@ -268,6 +268,7 @@ "actions/prompt_action_unittest.cc", "actions/save_generated_password_action_unittest.cc", "actions/select_option_action_unittest.cc", + "actions/set_attribute_action_unittest.cc", "actions/set_form_field_value_action_unittest.cc", "actions/show_details_action_unittest.cc", "actions/show_generic_ui_action_unittest.cc",
diff --git a/components/autofill_assistant/browser/actions/action_delegate.h b/components/autofill_assistant/browser/actions/action_delegate.h index 2991d32..f5265e8 100644 --- a/components/autofill_assistant/browser/actions/action_delegate.h +++ b/components/autofill_assistant/browser/actions/action_delegate.h
@@ -237,10 +237,10 @@ int key_press_delay_in_millisecond, base::OnceCallback<void(const ClientStatus&)> callback) = 0; - // Set the |value| of the |attribute| of the element given by |selector|. + // Set the |value| of all the |attributes| of the |element|. virtual void SetAttribute( - const Selector& selector, - const std::vector<std::string>& attribute, + const ElementFinder::Result& element, + const std::vector<std::string>& attributes, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback) = 0;
diff --git a/components/autofill_assistant/browser/actions/mock_action_delegate.h b/components/autofill_assistant/browser/actions/mock_action_delegate.h index a5f827e..47e174f5 100644 --- a/components/autofill_assistant/browser/actions/mock_action_delegate.h +++ b/components/autofill_assistant/browser/actions/mock_action_delegate.h
@@ -204,7 +204,7 @@ base::OnceCallback<void(const ClientStatus&)>& callback)); MOCK_METHOD4(SetAttribute, - void(const Selector& selector, + void(const ElementFinder::Result& element, const std::vector<std::string>& attribute, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback));
diff --git a/components/autofill_assistant/browser/actions/select_option_action.cc b/components/autofill_assistant/browser/actions/select_option_action.cc index ecb892cc..e3757a3 100644 --- a/components/autofill_assistant/browser/actions/select_option_action.cc +++ b/components/autofill_assistant/browser/actions/select_option_action.cc
@@ -13,18 +13,6 @@ #include "components/autofill_assistant/browser/client_status.h" namespace autofill_assistant { -namespace { - -void PerformSelectOption( - ActionDelegate* delegate, - const std::string& value, - DropdownSelectStrategy select_strategy, - const ElementFinder::Result& element, - base::OnceCallback<void(const ClientStatus&)> callback) { - delegate->SelectOption(element, value, select_strategy, std::move(callback)); -} - -} // namespace SelectOptionAction::SelectOptionAction(ActionDelegate* delegate, const ActionProto& proto) @@ -68,13 +56,22 @@ ActionDelegateUtil::FindElementAndPerform( delegate_, selector, - base::BindOnce(&PerformSelectOption, delegate_, + base::BindOnce(&SelectOptionAction::PerformSelectOption, + weak_ptr_factory_.GetWeakPtr(), proto_.select_option().selected_option(), proto_.select_option().select_strategy()), base::BindOnce(&SelectOptionAction::OnSelectOption, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } +void SelectOptionAction::PerformSelectOption( + const std::string& value, + DropdownSelectStrategy select_strategy, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> callback) { + delegate_->SelectOption(element, value, select_strategy, std::move(callback)); +} + void SelectOptionAction::OnSelectOption(ProcessActionCallback callback, const ClientStatus& status) { UpdateProcessedAction(status);
diff --git a/components/autofill_assistant/browser/actions/select_option_action.h b/components/autofill_assistant/browser/actions/select_option_action.h index ca632c4..e8b065d 100644 --- a/components/autofill_assistant/browser/actions/select_option_action.h +++ b/components/autofill_assistant/browser/actions/select_option_action.h
@@ -11,6 +11,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/autofill_assistant/browser/actions/action.h" +#include "components/autofill_assistant/browser/actions/action_delegate.h" +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/web/element_finder.h" namespace autofill_assistant { @@ -28,6 +31,11 @@ void OnWaitForElement(ProcessActionCallback callback, const Selector& selector, const ClientStatus& element_status); + void PerformSelectOption( + const std::string& value, + DropdownSelectStrategy select_strategy, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> callback); void OnSelectOption(ProcessActionCallback callback, const ClientStatus& status);
diff --git a/components/autofill_assistant/browser/actions/set_attribute_action.cc b/components/autofill_assistant/browser/actions/set_attribute_action.cc index b49213d..f612b99 100644 --- a/components/autofill_assistant/browser/actions/set_attribute_action.cc +++ b/components/autofill_assistant/browser/actions/set_attribute_action.cc
@@ -9,7 +9,9 @@ #include "base/bind.h" #include "base/callback.h" #include "components/autofill_assistant/browser/actions/action_delegate.h" +#include "components/autofill_assistant/browser/actions/action_delegate_util.h" #include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/web/element_finder.h" namespace autofill_assistant { @@ -44,13 +46,24 @@ return; } - delegate_->SetAttribute( - selector, ExtractVector(proto_.set_attribute().attribute()), - proto_.set_attribute().value(), + ActionDelegateUtil::FindElementAndPerform( + delegate_, selector, + base::BindOnce(&SetAttributeAction::PerformSetAttribute, + weak_ptr_factory_.GetWeakPtr(), + ExtractVector(proto_.set_attribute().attribute()), + proto_.set_attribute().value()), base::BindOnce(&SetAttributeAction::OnSetAttribute, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } +void SetAttributeAction::PerformSetAttribute( + const std::vector<std::string>& attributes, + const std::string& value, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> callback) { + delegate_->SetAttribute(element, attributes, value, std::move(callback)); +} + void SetAttributeAction::OnSetAttribute(ProcessActionCallback callback, const ClientStatus& status) { UpdateProcessedAction(status);
diff --git a/components/autofill_assistant/browser/actions/set_attribute_action.h b/components/autofill_assistant/browser/actions/set_attribute_action.h index 7bb43d2..f660ff9 100644 --- a/components/autofill_assistant/browser/actions/set_attribute_action.h +++ b/components/autofill_assistant/browser/actions/set_attribute_action.h
@@ -11,6 +11,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "components/autofill_assistant/browser/actions/action.h" +#include "components/autofill_assistant/browser/actions/action_delegate.h" +#include "components/autofill_assistant/browser/client_status.h" +#include "components/autofill_assistant/browser/web/element_finder.h" namespace autofill_assistant { @@ -28,6 +31,11 @@ void OnWaitForElement(ProcessActionCallback callback, const Selector& selector, const ClientStatus& element_status); + void PerformSetAttribute( + const std::vector<std::string>& attributes, + const std::string& value, + const ElementFinder::Result& element, + base::OnceCallback<void(const ClientStatus&)> callback); void OnSetAttribute(ProcessActionCallback callback, const ClientStatus& status);
diff --git a/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc b/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc new file mode 100644 index 0000000..8e25292d --- /dev/null +++ b/components/autofill_assistant/browser/actions/set_attribute_action_unittest.cc
@@ -0,0 +1,78 @@ +// Copyright 2020 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/autofill_assistant/browser/actions/set_attribute_action.h" + +#include "base/test/gmock_callback_support.h" +#include "base/test/mock_callback.h" +#include "components/autofill_assistant/browser/actions/action_test_utils.h" +#include "components/autofill_assistant/browser/actions/mock_action_delegate.h" +#include "components/autofill_assistant/browser/selector.h" +#include "components/autofill_assistant/browser/service.pb.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace autofill_assistant { +namespace { + +using ::base::test::RunOnceCallback; +using ::testing::_; +using ::testing::InSequence; +using ::testing::Pointee; +using ::testing::Property; + +class SetAttributeActionTest : public testing::Test { + public: + SetAttributeActionTest() {} + + void SetUp() override {} + + protected: + void Run() { + ActionProto action_proto; + *action_proto.mutable_set_attribute() = proto_; + SetAttributeAction action(&mock_action_delegate_, action_proto); + action.ProcessAction(callback_.Get()); + } + + MockActionDelegate mock_action_delegate_; + base::MockCallback<Action::ProcessActionCallback> callback_; + SetAttributeProto proto_; +}; + +TEST_F(SetAttributeActionTest, EmptySelectorFails) { + proto_.add_attribute("value"); + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, INVALID_SELECTOR)))); + Run(); +} + +TEST_F(SetAttributeActionTest, CheckExpectedCallChain) { + InSequence sequence; + + Selector selector({"#input"}); + *proto_.mutable_element() = selector.proto; + proto_.add_attribute("value"); + proto_.set_value("Hello World"); + + Selector expected_selector = selector; + EXPECT_CALL(mock_action_delegate_, + OnShortWaitForElement(expected_selector, _)) + .WillOnce(RunOnceCallback<1>(OkClientStatus())); + auto expected_element = + test_util::MockFindElement(mock_action_delegate_, expected_selector); + std::vector<std::string> expected_attributes = {"value"}; + EXPECT_CALL(mock_action_delegate_, + SetAttribute(EqualsElement(expected_element), expected_attributes, + "Hello World", _)) + .WillOnce(RunOnceCallback<3>(OkClientStatus())); + + EXPECT_CALL( + callback_, + Run(Pointee(Property(&ProcessedActionProto::status, ACTION_APPLIED)))); + Run(); +} + +} // namespace +} // namespace autofill_assistant
diff --git a/components/autofill_assistant/browser/script_executor.cc b/components/autofill_assistant/browser/script_executor.cc index a23021eb..60ee5f4 100644 --- a/components/autofill_assistant/browser/script_executor.cc +++ b/components/autofill_assistant/browser/script_executor.cc
@@ -588,11 +588,11 @@ } void ScriptExecutor::SetAttribute( - const Selector& selector, - const std::vector<std::string>& attribute, + const ElementFinder::Result& element, + const std::vector<std::string>& attributes, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback) { - delegate_->GetWebController()->SetAttribute(selector, attribute, value, + delegate_->GetWebController()->SetAttribute(element, attributes, value, std::move(callback)); }
diff --git a/components/autofill_assistant/browser/script_executor.h b/components/autofill_assistant/browser/script_executor.h index 790ce853..e84fb91 100644 --- a/components/autofill_assistant/browser/script_executor.h +++ b/components/autofill_assistant/browser/script_executor.h
@@ -191,8 +191,8 @@ int key_press_delay_in_millisecond, base::OnceCallback<void(const ClientStatus&)> callback) override; void SetAttribute( - const Selector& selector, - const std::vector<std::string>& attribute, + const ElementFinder::Result& element, + const std::vector<std::string>& attributes, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback) override; void SendKeyboardInput(
diff --git a/components/autofill_assistant/browser/web/web_controller.cc b/components/autofill_assistant/browser/web/web_controller.cc index 8e793c0..c571255e 100644 --- a/components/autofill_assistant/browser/web/web_controller.cc +++ b/components/autofill_assistant/browser/web/web_controller.cc
@@ -1267,40 +1267,20 @@ } void WebController::SetAttribute( - const Selector& selector, - const std::vector<std::string>& attribute, + const ElementFinder::Result& element, + const std::vector<std::string>& attributes, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback) { #ifdef NDEBUG - VLOG(3) << __func__ << " " << selector - << ", attribute=(redacted), value=(redacted)"; + VLOG(3) << __func__ << " attributes=(redacted), value=(redacted)"; #else - DVLOG(3) << __func__ << " " << selector << ", attribute=[" - << base::JoinString(attribute, ",") << "], value=" << value; + DVLOG(3) << __func__ << " attributes=[" << base::JoinString(attributes, ",") + << "], value=" << value; #endif - DCHECK(!selector.empty()); - DCHECK_GT(attribute.size(), 0u); - FindElement(selector, - /* strict_mode= */ true, - base::BindOnce(&WebController::OnFindElementForSetAttribute, - weak_ptr_factory_.GetWeakPtr(), attribute, value, - std::move(callback))); -} - -void WebController::OnFindElementForSetAttribute( - const std::vector<std::string>& attribute, - const std::string& value, - base::OnceCallback<void(const ClientStatus&)> callback, - const ClientStatus& status, - std::unique_ptr<ElementFinder::Result> element_result) { - if (!status.ok()) { - std::move(callback).Run(status); - return; - } - + DCHECK_GT(attributes.size(), 0u); base::Value::ListStorage attribute_values; - for (const std::string& string : attribute) { + for (const std::string& string : attributes) { attribute_values.emplace_back(base::Value(string)); } @@ -1309,23 +1289,15 @@ AddRuntimeCallArgument(value, &arguments); devtools_client_->GetRuntime()->CallFunctionOn( runtime::CallFunctionOnParams::Builder() - .SetObjectId(element_result->object_id) + .SetObjectId(element.object_id) .SetArguments(std::move(arguments)) .SetFunctionDeclaration(std::string(kSetAttributeScript)) .Build(), - element_result->node_frame_id, - base::BindOnce(&WebController::OnSetAttribute, + element.node_frame_id, + base::BindOnce(&WebController::OnJavaScriptResult, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } -void WebController::OnSetAttribute( - base::OnceCallback<void(const ClientStatus&)> callback, - const DevtoolsClient::ReplyStatus& reply_status, - std::unique_ptr<runtime::CallFunctionOnResult> result) { - std::move(callback).Run( - CheckJavaScriptResult(reply_status, result.get(), __FILE__, __LINE__)); -} - void WebController::SendKeyboardInput( const ElementFinder::Result& element, const std::vector<UChar32>& codepoints,
diff --git a/components/autofill_assistant/browser/web/web_controller.h b/components/autofill_assistant/browser/web/web_controller.h index 36793be..8a62a15 100644 --- a/components/autofill_assistant/browser/web/web_controller.h +++ b/components/autofill_assistant/browser/web/web_controller.h
@@ -162,10 +162,10 @@ int key_press_delay_in_millisecond, base::OnceCallback<void(const ClientStatus&)> callback); - // Set the |value| of the |attribute| of the element given by |selector|. + // Set the |value| of all the |attributes| of the |element|. virtual void SetAttribute( - const Selector& selector, - const std::vector<std::string>& attribute, + const ElementFinder::Result& element, + const std::vector<std::string>& attributes, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback); @@ -442,15 +442,6 @@ const ElementFinder::Result& element, const std::string& value, base::OnceCallback<void(const ClientStatus&)> callback); - void OnFindElementForSetAttribute( - const std::vector<std::string>& attribute, - const std::string& value, - base::OnceCallback<void(const ClientStatus&)> callback, - const ClientStatus& status, - std::unique_ptr<ElementFinder::Result> element_result); - void OnSetAttribute(base::OnceCallback<void(const ClientStatus&)> callback, - const DevtoolsClient::ReplyStatus& reply_status, - std::unique_ptr<runtime::CallFunctionOnResult> result); void OnFindElementForGetOuterHtml( base::OnceCallback<void(const ClientStatus&, const std::string&)> callback,
diff --git a/components/autofill_assistant/browser/web/web_controller_browsertest.cc b/components/autofill_assistant/browser/web/web_controller_browsertest.cc index a103739..c36ea7b 100644 --- a/components/autofill_assistant/browser/web/web_controller_browsertest.cc +++ b/components/autofill_assistant/browser/web/web_controller_browsertest.cc
@@ -572,24 +572,41 @@ } ClientStatus SetAttribute(const Selector& selector, - const std::vector<std::string>& attribute, + const std::vector<std::string>& attributes, const std::string& value) { base::RunLoop run_loop; ClientStatus result; - web_controller_->SetAttribute( - selector, attribute, value, - base::BindOnce(&WebControllerBrowserTest::OnSetAttribute, - base::Unretained(this), run_loop.QuitClosure(), - &result)); + + web_controller_->FindElement( + selector, /* strict_mode= */ true, + base::BindOnce( + &WebControllerBrowserTest::FindSetAttributeElementCallback, + base::Unretained(this), attributes, value, run_loop.QuitClosure(), + &result)); + run_loop.Run(); return result; } - void OnSetAttribute(base::OnceClosure done_callback, - ClientStatus* result_output, - const ClientStatus& status) { - *result_output = status; - std::move(done_callback).Run(); + void FindSetAttributeElementCallback( + const std::vector<std::string>& attributes, + const std::string& value, + base::OnceClosure done_callback, + ClientStatus* result_output, + const ClientStatus& status, + std::unique_ptr<ElementFinder::Result> element_result) { + if (!status.ok()) { + *result_output = status; + std::move(done_callback).Run(); + return; + } + + ASSERT_TRUE(element_result != nullptr); + web_controller_->SetAttribute( + *element_result, attributes, value, + base::BindOnce(&WebControllerBrowserTest::ElementRetainingCallback, + base::Unretained(this), std::move(element_result), + std::move(done_callback), result_output)); } bool GetElementPosition(const Selector& selector, RectF* rect_output) {
diff --git a/components/exo/wayland/wayland_display_observer.cc b/components/exo/wayland/wayland_display_observer.cc index 00fb373..aa9b2db5 100644 --- a/components/exo/wayland/wayland_display_observer.cc +++ b/components/exo/wayland/wayland_display_observer.cc
@@ -115,11 +115,10 @@ if (wl_resource_get_version(output_resource_) >= WL_OUTPUT_SCALE_SINCE_VERSION) { - // Sending 100% if the scale is less then 100%, because wl_output_send_scale - // doesn't support fractional scale. - wl_output_send_scale( - output_resource_, - std::max(1, static_cast<int32_t>(display.device_scale_factor()))); + // wl_output only supports integer scaling, so if device scale factor is + // fractional we need to round it up to the closest integer. + wl_output_send_scale(output_resource_, + std::ceil(display.device_scale_factor())); } // TODO(reveman): Send real list of modes.
diff --git a/components/performance_manager/service_worker_context_adapter.cc b/components/performance_manager/service_worker_context_adapter.cc index 547f342..2e9b5114 100644 --- a/components/performance_manager/service_worker_context_adapter.cc +++ b/components/performance_manager/service_worker_context_adapter.cc
@@ -111,7 +111,7 @@ } void ServiceWorkerContextAdapter::CountExternalRequestsForTest( - const GURL& origin, + const url::Origin& origin, CountExternalRequestsCallback callback) { NOTIMPLEMENTED(); }
diff --git a/components/performance_manager/service_worker_context_adapter.h b/components/performance_manager/service_worker_context_adapter.h index ff74724..88d60fa 100644 --- a/components/performance_manager/service_worker_context_adapter.h +++ b/components/performance_manager/service_worker_context_adapter.h
@@ -59,7 +59,7 @@ int64_t service_worker_version_id, const std::string& request_uuid) override; void CountExternalRequestsForTest( - const GURL& origin, + const url::Origin& origin, CountExternalRequestsCallback callback) override; bool MaybeHasRegistrationForOrigin(const url::Origin& origin) override; void GetInstalledRegistrationOrigins(
diff --git a/components/viz/common/frame_sinks/begin_frame_args.h b/components/viz/common/frame_sinks/begin_frame_args.h index 53f54a2..32caac91 100644 --- a/components/viz/common/frame_sinks/begin_frame_args.h +++ b/components/viz/common/frame_sinks/begin_frame_args.h
@@ -124,6 +124,12 @@ return base::TimeDelta::FromSeconds(0); } + // This is the preferred interval to use when the producer doesn't have any + // frame rate preference. The Display can use any value which is appropriate. + static constexpr base::TimeDelta MaxInterval() { + return base::TimeDelta::Max(); + } + // This is a hard-coded deadline adjustment used by the display compositor. // Using 1/3 of the vsync as the default adjustment gives the display // compositor the last 1/3 of a frame to produce output, the client impl
diff --git a/components/viz/service/display/frame_rate_decider.cc b/components/viz/service/display/frame_rate_decider.cc index 4d0dd48..624ca8f 100644 --- a/components/viz/service/display/frame_rate_decider.cc +++ b/components/viz/service/display/frame_rate_decider.cc
@@ -45,6 +45,12 @@ hw_support_for_multiple_refresh_rates_( hw_support_for_multiple_refresh_rates), supports_set_frame_rate_(supports_set_frame_rate) { + // For sources which have no preference, allow lowering them to up to + // 24Hz. + double interval_in_seconds = 1.0 / 24.0; + frame_interval_for_sinks_with_no_preference_ = + base::TimeDelta::FromSecondsD(interval_in_seconds); + surface_manager_->AddObserver(this); } @@ -116,18 +122,8 @@ if (!multiple_refresh_rates_supported()) return; - // If lowering the refresh rate is supported by the platform then we do this - // in all cases where the content drawing onscreen animates at a fixed rate. - // This includes surfaces backed by videos or media streams (since the frame - // rate provided by LayerTree is an estimate, it is not considered a fixed - // frame source). This allows the platform to refresh the screen at a lower - // rate which is power efficient. - // - // However if we're using a synthetic begin frame source, then the - // optimization is restricted to cases with multiple media streams. This is - // because using this for all video cases results in dropped frame regressions - // which need to be investigated (see crbug.com/976583). int num_of_frame_sinks_with_fixed_interval = 0; + int num_of_frame_sinks_with_no_preference = 0; for (const auto& frame_sink_id : frame_sinks_drawn_in_previous_frame_) { auto type = mojom::CompositorFrameSinkType::kUnspecified; auto interval = @@ -138,20 +134,21 @@ DCHECK_EQ(interval, BeginFrameArgs::MinInterval()); continue; case mojom::CompositorFrameSinkType::kVideo: - if (hw_support_for_multiple_refresh_rates_) - num_of_frame_sinks_with_fixed_interval++; + num_of_frame_sinks_with_fixed_interval++; break; case mojom::CompositorFrameSinkType::kMediaStream: num_of_frame_sinks_with_fixed_interval++; break; case mojom::CompositorFrameSinkType::kLayerTree: - continue; + if (interval == BeginFrameArgs::MaxInterval()) { + num_of_frame_sinks_with_no_preference++; + } + break; } } - const int min_frame_sinks_to_toggle = - hw_support_for_multiple_refresh_rates_ ? 1 : 2; - if (num_of_frame_sinks_with_fixed_interval < min_frame_sinks_to_toggle) { + if (!ShouldToggleFrameInterval(num_of_frame_sinks_with_fixed_interval, + num_of_frame_sinks_with_no_preference)) { TRACE_EVENT_INSTANT0( "viz", "FrameRateDecider::UpdatePreferredFrameIntervalIfNeeded - not enough " @@ -172,6 +169,9 @@ for (const auto& frame_sink_id : frame_sinks_updated_in_previous_frame_) { auto interval = client_->GetPreferredFrameIntervalForFrameSinkId(frame_sink_id); + if (interval == BeginFrameArgs::MaxInterval()) { + interval = frame_interval_for_sinks_with_no_preference_; + } if (!min_frame_sink_interval) { min_frame_sink_interval = interval; continue; @@ -181,8 +181,12 @@ all_frame_sinks_have_same_interval = false; min_frame_sink_interval = std::min(*min_frame_sink_interval, interval); } - if (!min_frame_sink_interval) - min_frame_sink_interval = BeginFrameArgs::MinInterval(); + + // A redraw was done with no onscreen content getting updated, avoid updating + // the interval in this case. + if (!min_frame_sink_interval) { + return; + } TRACE_EVENT_INSTANT1("viz", "FrameRateDecider::UpdatePreferredFrameIntervalIfNeeded", @@ -214,6 +218,29 @@ SetPreferredInterval(new_preferred_interval); } +bool FrameRateDecider::ShouldToggleFrameInterval( + int num_of_frame_sinks_with_fixed_interval, + int num_of_frame_sinks_with_no_preference) const { + // If there is no fixed rate content, we don't try to lower the frame rate. + if (num_of_frame_sinks_with_fixed_interval == 0) + return false; + + // If lowering the refresh rate is supported by the platform then we try to + // do this in all cases where any content drawing onscreen animates at a + // fixed rate. This includes surfaces backed by videos or media streams. + if (hw_support_for_multiple_refresh_rates_) + return num_of_frame_sinks_with_fixed_interval > 0; + + // If we're reducing frame rate for the display compositor, as opposed to the + // underlying platform compositor or physical display, then restrict it to + // cases with multiple animating sources that can be lowered. We should be + // able to do it for all video cases but this results in dropped frame + // regressions which need to be investigated (see crbug.com/976583). + return num_of_frame_sinks_with_fixed_interval + + num_of_frame_sinks_with_no_preference > + 1; +} + void FrameRateDecider::SetPreferredInterval( base::TimeDelta new_preferred_interval) { TRACE_EVENT_INSTANT1("viz", "FrameRateDecider::SetPreferredInterval",
diff --git a/components/viz/service/display/frame_rate_decider.h b/components/viz/service/display/frame_rate_decider.h index 319b140..638fe62 100644 --- a/components/viz/service/display/frame_rate_decider.h +++ b/components/viz/service/display/frame_rate_decider.h
@@ -72,6 +72,10 @@ void set_min_num_of_frames_to_toggle_interval_for_testing(size_t num) { min_num_of_frames_to_toggle_interval_ = num; } + void set_frame_interval_for_sinks_with_no_preference_for_testing( + base::TimeDelta interval) { + frame_interval_for_sinks_with_no_preference_ = interval; + } // SurfaceObserver implementation. void OnSurfaceWillBeDrawn(Surface* surface) override; @@ -81,6 +85,10 @@ void EndAggregation(); void UpdatePreferredFrameIntervalIfNeeded(); void SetPreferredInterval(base::TimeDelta new_preferred_interval); + bool ShouldToggleFrameInterval( + int num_of_frame_sinks_with_fixed_interval, + int num_of_frame_sinks_with_no_preference) const; + bool multiple_refresh_rates_supported() const; bool inside_surface_aggregation_ = false; @@ -97,6 +105,8 @@ base::TimeDelta current_preferred_frame_interval_; size_t min_num_of_frames_to_toggle_interval_; + base::TimeDelta frame_interval_for_sinks_with_no_preference_; + SurfaceManager* const surface_manager_; Client* const client_; const bool hw_support_for_multiple_refresh_rates_;
diff --git a/components/viz/service/display/frame_rate_decider_unittest.cc b/components/viz/service/display/frame_rate_decider_unittest.cc index 8a651a1..1e357a47 100644 --- a/components/viz/service/display/frame_rate_decider_unittest.cc +++ b/components/viz/service/display/frame_rate_decider_unittest.cc
@@ -45,8 +45,12 @@ base::TimeDelta GetPreferredFrameIntervalForFrameSinkId( const FrameSinkId& id, mojom::CompositorFrameSinkType* type) override { - if (type) - *type = mojom::CompositorFrameSinkType::kMediaStream; + if (type) { + auto it = frame_sink_types_.find(id); + *type = it == frame_sink_types_.end() + ? mojom::CompositorFrameSinkType::kMediaStream + : it->second; + } return preferred_intervals_[id]; } @@ -90,6 +94,7 @@ base::TimeDelta display_interval_; base::flat_map<FrameSinkId, base::TimeDelta> preferred_intervals_; + base::flat_map<FrameSinkId, mojom::CompositorFrameSinkType> frame_sink_types_; std::unique_ptr<SurfaceManager> surface_manager_; std::unique_ptr<FrameRateDecider> frame_rate_decider_; @@ -112,12 +117,12 @@ EXPECT_EQ(display_interval_, preferred_interval); // Do a draw with the same surface and same CompositorFrame. Its assumed that - // the surface is not being updated and we toggle back to the min interval. + // the surface is not being updated and we retain the current state. { FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); frame_rate_decider_->OnSurfaceWillBeDrawn(surface); } - EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); + EXPECT_EQ(display_interval_, preferred_interval); // Submit a new frame to this surface and draw again. The interval should be // set to the surface's preferred rate. @@ -143,12 +148,12 @@ EXPECT_EQ(display_interval_, preferred_interval); // Do a draw with the same surface and same CompositorFrame. Its assumed that - // the surface is not being updated and we toggle back to the min interval. + // no content changed onscreen and we retain the current state. { FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); frame_rate_decider_->OnSurfaceWillBeDrawn(surface); } - EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); + EXPECT_EQ(display_interval_, preferred_interval); // Create a new surface with the same frame sink id. The interval should be // set to the surface's preferred rate. @@ -395,5 +400,113 @@ EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); } +// If there are no fixed frame sources, we should not lower the frame interval. +TEST_F(FrameRateDeciderTest, NoFixedIntervalSurfaces) { + base::TimeDelta min_supported_interval = base::TimeDelta::FromSeconds(1); + const std::vector<base::TimeDelta> supported_intervals = { + min_supported_interval * 3, min_supported_interval * 2, + min_supported_interval}; + frame_rate_decider_->SetSupportedFrameIntervals(supported_intervals); + EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); + + Surface* surfaces[3]; + for (int i = 0; i < 3; ++i) { + FrameSinkId frame_sink_id(1u, i); + preferred_intervals_[frame_sink_id] = BeginFrameArgs::MaxInterval(); + frame_sink_types_[frame_sink_id] = + mojom::CompositorFrameSinkType::kLayerTree; + surfaces[i] = CreateAndDrawSurface(frame_sink_id); + } + + for (int i = 0; i < 3; ++i) + UpdateFrame(surfaces[i]); + { + FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); + for (int i = 0; i < 3; ++i) + frame_rate_decider_->OnSurfaceWillBeDrawn(surfaces[i]); + } + EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); +} + +TEST_F(FrameRateDeciderTest, NoHwSupportForMultiRefreshRates) { + bool hw_support_for_multiple_refresh_rate = false; + frame_rate_decider_ = std::make_unique<FrameRateDecider>( + surface_manager_.get(), this, hw_support_for_multiple_refresh_rate, false, + 0); + base::TimeDelta min_supported_interval = base::TimeDelta::FromSeconds(1); + const std::vector<base::TimeDelta> supported_intervals = { + min_supported_interval * 3, min_supported_interval * 2, + min_supported_interval}; + frame_rate_decider_ + ->set_frame_interval_for_sinks_with_no_preference_for_testing( + min_supported_interval); + frame_rate_decider_->SetSupportedFrameIntervals(supported_intervals); + EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); + + FrameSinkId video_frame_sink_id(1u, 1u); + Surface* video_surface = CreateAndDrawSurface(video_frame_sink_id); + preferred_intervals_[video_frame_sink_id] = min_supported_interval; + frame_sink_types_[video_frame_sink_id] = + mojom::CompositorFrameSinkType::kVideo; + + FrameSinkId stream_frame_sink_id(1u, 2u); + Surface* stream_surface = CreateAndDrawSurface(stream_frame_sink_id); + preferred_intervals_[stream_frame_sink_id] = min_supported_interval; + frame_sink_types_[stream_frame_sink_id] = + mojom::CompositorFrameSinkType::kMediaStream; + + FrameSinkId content_frame_sink_id(1u, 3u); + Surface* content_surface = CreateAndDrawSurface(content_frame_sink_id); + preferred_intervals_[content_frame_sink_id] = BeginFrameArgs::MaxInterval(); + frame_sink_types_[content_frame_sink_id] = + mojom::CompositorFrameSinkType::kLayerTree; + + // Only 1 fixed rate source, frame interval is unchanged. + { + FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); + UpdateFrame(video_surface); + frame_rate_decider_->OnSurfaceWillBeDrawn(video_surface); + } + EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); + + // Multiple fixed rate sources, frame interval is lowered. + { + FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); + frame_rate_decider_->OnSurfaceWillBeDrawn(video_surface); + frame_rate_decider_->OnSurfaceWillBeDrawn(stream_surface); + } + EXPECT_EQ(display_interval_, min_supported_interval); + + // One fixed rate source + content source with no preference, frame interval + // is lowered. + { + FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); + frame_rate_decider_->OnSurfaceWillBeDrawn(video_surface); + frame_rate_decider_->OnSurfaceWillBeDrawn(content_surface); + } + EXPECT_EQ(display_interval_, min_supported_interval); + + // The content source opts out of no preference, frame interval is not + // lowered. + { + FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); + preferred_intervals_[content_frame_sink_id] = BeginFrameArgs::MinInterval(); + frame_rate_decider_->OnSurfaceWillBeDrawn(video_surface); + frame_rate_decider_->OnSurfaceWillBeDrawn(content_surface); + } + EXPECT_EQ(display_interval_, FrameRateDecider::UnspecifiedFrameInterval()); + + // Multiple fixed rate sources + content source with estimated interval. + // Frame rate is lowered. + { + FrameRateDecider::ScopedAggregate scope(frame_rate_decider_.get()); + preferred_intervals_[content_frame_sink_id] = min_supported_interval; + frame_rate_decider_->OnSurfaceWillBeDrawn(video_surface); + frame_rate_decider_->OnSurfaceWillBeDrawn(stream_surface); + frame_rate_decider_->OnSurfaceWillBeDrawn(content_surface); + } + EXPECT_EQ(display_interval_, min_supported_interval); +} + } // namespace } // namespace viz
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc index 67a9a8f..af487cf8 100644 --- a/content/browser/devtools/protocol/network_handler.cc +++ b/content/browser/devtools/protocol/network_handler.cc
@@ -13,6 +13,8 @@ #include "base/bind.h" #include "base/command_line.h" #include "base/containers/queue.h" +#include "base/i18n/i18n_constants.h" +#include "base/i18n/icu_string_conversions.h" #include "base/json/json_reader.h" #include "base/process/process_handle.h" #include "base/strings/string_number_conversions.h" @@ -465,9 +467,16 @@ for (const auto& header : headers) { std::string value; bool merge_with_another = headers_dict->getString(header->key, &value); + std::string header_value; + if (!base::ConvertToUtf8AndNormalize(header->value, base::kCodepageLatin1, + &header_value)) { + // For response headers, the encoding could be anything, so conversion + // might fail; in that case this is the most useful thing we can do. + header_value = header->value; + } headers_dict->setString(header->key, merge_with_another - ? value + '\n' + header->value - : header->value); + ? value + '\n' + header_value + : header_value); } return Object::fromValue(headers_dict.get(), nullptr); }
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.cc b/content/browser/renderer_host/agent_scheduling_group_host.cc index 3c0b8b39..ece415c 100644 --- a/content/browser/renderer_host/agent_scheduling_group_host.cc +++ b/content/browser/renderer_host/agent_scheduling_group_host.cc
@@ -5,10 +5,13 @@ #include <memory> +#include "base/feature_list.h" #include "base/supports_user_data.h" #include "content/browser/renderer_host/render_process_host_impl.h" +#include "content/common/agent_scheduling_group.mojom.h" #include "content/common/renderer.mojom.h" #include "content/public/browser/render_process_host.h" +#include "content/public/common/content_features.h" namespace content { @@ -16,8 +19,14 @@ using ::IPC::ChannelProxy; using ::IPC::Listener; +using ::mojo::AssociatedReceiver; +using ::mojo::AssociatedRemote; +using ::mojo::PendingAssociatedReceiver; +using ::mojo::PendingAssociatedRemote; +using ::mojo::PendingReceiver; using ::mojo::PendingRemote; using ::mojo::Receiver; +using ::mojo::Remote; static constexpr char kAgentGroupHostDataKey[] = "AgentSchedulingGroupHostUserDataKey"; @@ -39,6 +48,63 @@ } // namespace +// MaybeAssociatedReceiver: +AgentSchedulingGroupHost::MaybeAssociatedReceiver::MaybeAssociatedReceiver( + AgentSchedulingGroupHost& host, + bool should_associate) { + if (should_associate) { + receiver_.emplace<AssociatedReceiver<mojom::AgentSchedulingGroupHost>>( + &host); + } else { + receiver_.emplace<Receiver<mojom::AgentSchedulingGroupHost>>(&host); + } +} + +AgentSchedulingGroupHost::MaybeAssociatedReceiver::~MaybeAssociatedReceiver() = + default; + +PendingRemote<mojom::AgentSchedulingGroupHost> +AgentSchedulingGroupHost::MaybeAssociatedReceiver::BindNewPipeAndPassRemote() { + return absl::get<Receiver<mojom::AgentSchedulingGroupHost>>(receiver_) + .BindNewPipeAndPassRemote(); +} + +PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> +AgentSchedulingGroupHost::MaybeAssociatedReceiver:: + BindNewEndpointAndPassRemote() { + return absl::get<AssociatedReceiver<mojom::AgentSchedulingGroupHost>>( + receiver_) + .BindNewEndpointAndPassRemote(); +} + +// MaybeAssociatedRemote: +AgentSchedulingGroupHost::MaybeAssociatedRemote::MaybeAssociatedRemote( + bool should_associate) { + if (should_associate) { + remote_ = AssociatedRemote<mojom::AgentSchedulingGroup>(); + } else { + remote_ = Remote<mojom::AgentSchedulingGroup>(); + } +} + +AgentSchedulingGroupHost::MaybeAssociatedRemote::~MaybeAssociatedRemote() = + default; + +PendingReceiver<mojom::AgentSchedulingGroup> +AgentSchedulingGroupHost::MaybeAssociatedRemote::BindNewPipeAndPassReceiver() { + return absl::get<Remote<mojom::AgentSchedulingGroup>>(remote_) + .BindNewPipeAndPassReceiver(); +} + +PendingAssociatedReceiver<mojom::AgentSchedulingGroup> +AgentSchedulingGroupHost::MaybeAssociatedRemote:: + BindNewEndpointAndPassReceiver() { + return absl::get<AssociatedRemote<mojom::AgentSchedulingGroup>>(remote_) + .BindNewEndpointAndPassReceiver(); +} + +// AgentSchedulingGroupHost: + // static AgentSchedulingGroupHost* AgentSchedulingGroupHost::Get( const SiteInstance& instance, @@ -57,11 +123,26 @@ } AgentSchedulingGroupHost::AgentSchedulingGroupHost(RenderProcessHost& process) - : process_(process) { + : AgentSchedulingGroupHost( + process, + !base::FeatureList::IsEnabled( + features::kMbiDetachAgentSchedulingGroupFromChannel)) {} + +AgentSchedulingGroupHost::AgentSchedulingGroupHost(RenderProcessHost& process, + bool should_associate) + : process_(process), + receiver_(*this, should_associate), + mojo_remote_(should_associate) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - process_.GetRendererInterface()->CreateAgentSchedulingGroup( - receiver_.BindNewPipeAndPassRemote(), - mojo_remote_.BindNewPipeAndPassReceiver()); + if (should_associate) { + process_.GetRendererInterface()->CreateAssociatedAgentSchedulingGroup( + receiver_.BindNewEndpointAndPassRemote(), + mojo_remote_.BindNewEndpointAndPassReceiver()); + } else { + process_.GetRendererInterface()->CreateAgentSchedulingGroup( + receiver_.BindNewPipeAndPassRemote(), + mojo_remote_.BindNewPipeAndPassReceiver()); + } } // DO NOT USE |process_| HERE! At this point it (or at least parts of it) is no
diff --git a/content/browser/renderer_host/agent_scheduling_group_host.h b/content/browser/renderer_host/agent_scheduling_group_host.h index 94ec65a3..5273bbe 100644 --- a/content/browser/renderer_host/agent_scheduling_group_host.h +++ b/content/browser/renderer_host/agent_scheduling_group_host.h
@@ -11,8 +11,11 @@ #include "content/common/associated_interfaces.mojom-forward.h" #include "content/common/content_export.h" #include "content/common/renderer.mojom-forward.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/variant.h" namespace IPC { class ChannelProxy; @@ -43,7 +46,8 @@ static AgentSchedulingGroupHost* Get(const SiteInstance& instance, RenderProcessHost& process); - // Should not be called explicitly. Use Get() instead. + // Utility ctor, forwarding to the main ctor below. + // Should not be called explicitly. Use `Get()` instead. explicit AgentSchedulingGroupHost(RenderProcessHost& process); ~AgentSchedulingGroupHost() override; @@ -64,16 +68,70 @@ void DestroyView(int32_t routing_id); private: + // `MaybeAssociatedReceiver` and `MaybeAssociatedRemote` are temporary helper + // classes that allow us to switch between using associated and non-associated + // mojo interfaces. This behavior is controlled by the + // `kMbiDetachAgentSchedulingGroupFromChannel` feature flag. + // Associated interfaces are associated with the IPC channel (transitively, + // via the `Renderer` interface), thus preserving cross-agent scheduling group + // message order. Non-associated interfaces are independent from each other + // and do not preserve message order between agent scheduling groups. + // TODO(crbug.com/1111231): Remove these once we can remove the flag. + class MaybeAssociatedReceiver { + public: + MaybeAssociatedReceiver(AgentSchedulingGroupHost& host, + bool should_associate); + ~MaybeAssociatedReceiver(); + + mojo::PendingRemote<mojom::AgentSchedulingGroupHost> + BindNewPipeAndPassRemote() WARN_UNUSED_RESULT; + mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> + BindNewEndpointAndPassRemote() WARN_UNUSED_RESULT; + + private: + absl::variant< + // This is required to make the variant default constructible. After the + // ctor body finishes, the variant will never hold this alternative. + absl::monostate, + mojo::Receiver<mojom::AgentSchedulingGroupHost>, + mojo::AssociatedReceiver<mojom::AgentSchedulingGroupHost>> + receiver_; + }; + + class MaybeAssociatedRemote { + public: + explicit MaybeAssociatedRemote(bool should_associate); + ~MaybeAssociatedRemote(); + + mojo::PendingReceiver<mojom::AgentSchedulingGroup> + BindNewPipeAndPassReceiver() WARN_UNUSED_RESULT; + mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> + BindNewEndpointAndPassReceiver() WARN_UNUSED_RESULT; + + private: + absl::variant<mojo::Remote<mojom::AgentSchedulingGroup>, + mojo::AssociatedRemote<mojom::AgentSchedulingGroup>> + remote_; + }; + + // Main constructor. + // |should_associate| determines whether the `AgentSchedulingGroupHost` and + // `AgentSchedulingGroup` mojos should be associated with the `Renderer` or + // not. If they are, message order will be preserved across the entire + // process. If not, ordering will only be preserved inside an + // `AgentSchedulingGroup`. + AgentSchedulingGroupHost(RenderProcessHost& process, bool should_associate); + // The RenderProcessHost this AgentSchedulingGroup is assigned to. RenderProcessHost& process_; // Implementation of `mojom::AgentSchedulingGroupHost`, used for responding to // calls from the (renderer-side) `AgentSchedulingGroup`. - mojo::Receiver<mojom::AgentSchedulingGroupHost> receiver_{this}; + MaybeAssociatedReceiver receiver_; // Remote stub of `mojom::AgentSchedulingGroup`, used for sending calls to the // (renderer-side) `AgentSchedulingGroup`. - mojo::Remote<mojom::AgentSchedulingGroup> mojo_remote_; + MaybeAssociatedRemote mojo_remote_; }; } // namespace content
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc index 823233d..f59b32c 100644 --- a/content/browser/renderer_host/navigator.cc +++ b/content/browser/renderer_host/navigator.cc
@@ -397,7 +397,8 @@ !navigation_request->IsServedFromBackForwardCache() && !is_same_document_navigation && !was_within_same_document; - render_frame_host->DidNavigate(params, did_create_new_document); + render_frame_host->DidNavigate(params, navigation_request.get(), + did_create_new_document); // Send notification about committed provisional loads. This notification is // different from the NAV_ENTRY_COMMITTED notification which doesn't include
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc index 1f5ae2cd..be8c261 100644 --- a/content/browser/renderer_host/render_frame_host_impl.cc +++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -2421,6 +2421,7 @@ void RenderFrameHostImpl::DidNavigate( const FrameHostMsg_DidCommitProvisionalLoad_Params& params, + NavigationRequest* navigation_request, bool did_create_new_document) { // Keep track of the last committed URL and origin in the RenderFrameHost // itself. These allow GetLastCommittedURL and GetLastCommittedOrigin to @@ -2439,28 +2440,12 @@ if (!params.url_is_unreachable) last_successful_url_ = params.url; - if (did_create_new_document) { - // After setting the last committed origin, reset the feature policy and - // sandbox flags in the RenderFrameHost to a blank policy based on the - // parent frame or opener frame. - ResetFeaturePolicy(); - active_sandbox_flags_ = frame_tree_node()->active_sandbox_flags(); - document_policy_ = blink::DocumentPolicy::CreateWithHeaderPolicy({}); - - // Since we're changing documents, we should reset the event handler - // trackers. - has_before_unload_handler_ = false; - has_unload_handler_ = false; - has_pagehide_handler_ = false; - has_visibilitychange_handler_ = false; - - DCHECK(params.embedding_token.has_value()); - SetEmbeddingToken(params.embedding_token.value()); - } - // Reset the salt so that media device IDs are reset after the new navigation // if necessary. media_device_id_salt_base_ = BrowserContext::CreateRandomMediaDeviceIDSalt(); + + if (did_create_new_document) + DidCommitNewDocument(params, navigation_request); } void RenderFrameHostImpl::SetLastCommittedOrigin(const url::Origin& origin) { @@ -8313,8 +8298,15 @@ navigation_request->set_has_user_gesture(params->gesture == NavigationGestureUser); + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation might not be right. Should this be moved to + // DidCommitNewDocument()? last_http_status_code_ = params->http_status_code; + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation might not be right. Should this be moved to + // DidCommitNewDocument()? last_http_method_ = params->method; + UpdateSiteURL(params->url, params->url_is_unreachable); if (!is_same_document_navigation) UpdateRenderProcessHostFramePriorities(); @@ -8323,11 +8315,20 @@ // are certain security checks that we cannot apply to subframes in MHTML // documents. Do not trust renderer data when determining that, rather use // the |navigation_request|, which was generated and stays browser side. + // + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation is NOT correct. This should be moved to DidCommitNewDocument(). is_mhtml_document_ = (navigation_request->GetMimeType() == "multipart/related" || navigation_request->GetMimeType() == "message/rfc822"); + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation might not be right. Should this be moved to + // DidCommitNewDocument()? accessibility_reset_count_ = 0; + + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation isn't right. This should be moved to DidCommitNewDocument(). appcache_handle_ = navigation_request->TakeAppCacheHandle(); bool created_new_document = @@ -8374,15 +8375,6 @@ document_used_web_otp_ = false; } - // Keep track of the sandbox policy of the document that has just committed. - // It will be compared with the value computed from the renderer. The latter - // is expected to be received in DidSetFramePolicyHeaders(..). - base::Optional<network::mojom::WebSandboxFlags> active_sandbox_flags_control = - navigation_request->SandboxFlagsToCommit(); - - int virtual_browsing_context_group = - navigation_request->coop_status().virtual_browsing_context_group(); - // If we still have a PeakGpuMemoryTracker, then the loading it was observing // never completed. Cancel it's callback so that we don't report partial // loads to UMA. @@ -8390,78 +8382,108 @@ loading_mem_tracker_->Cancel(); // Main Frames will create the tracker, which will be triggered after we // receive DidStopLoading. + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation isn't right. This should be moved to DidCommitNewDocument(). loading_mem_tracker_ = navigation_request->TakePeakGpuMemoryTracker(); - if (created_new_document) { - cross_origin_opener_policy_ = - navigation_request->coop_status().current_coop(); - } - - network::mojom::ClientSecurityStatePtr client_security_state = - navigation_request->TakeClientSecurityState(); - std::unique_ptr<CrossOriginEmbedderPolicyReporter> coep_reporter = - navigation_request->TakeCoepReporter(); - std::unique_ptr<CrossOriginOpenerPolicyReporter> coop_reporter = - navigation_request->coop_status().TakeCoopReporter(); - - network::mojom::ContentSecurityPolicyPtr required_csp = - navigation_request->TakeRequiredCSP(); - - // TODO(arthursonzogni, altimin): By taking ownership and deleting the - // NavigationRequest, this line triggers the DidFinishNavigation event. There - // are several document's associated state assigned below when a new document - // is created. We might prefer to fully update the RenderFrameHost before - // dispatching the event. frame_tree_node()->navigator().DidNavigate(this, *params, std::move(navigation_request), is_same_document_navigation); // Reset back the state to false after navigation commits. + // TODO(https://crbug.com/1072817): Undo this plumbing after removing the + // early post-crash CommitPending() call. committed_speculative_rfh_before_navigation_commit_ = false; + // TODO(arthursonzogni): Updating this flag for same-document or bfcache + // navigation doesn't seem right. This should likely be executed in + // DidCommitNewDocument(). if (IsBackForwardCacheEnabled()) { // Store the Commit params so they can be reused if the page is ever // restored from the BackForwardCache. last_commit_params_ = std::move(params); } - // TODO(arthursonzogni): Investigate what must be done when - // navigation_request->IsWaitingToCommit() is false here. - if (created_new_document) { - renderer_reported_scheduler_tracked_features_ = 0; - browser_reported_scheduler_tracked_features_ = 0; - last_committed_client_security_state_ = std::move(client_security_state); - active_sandbox_flags_control_ = std::move(active_sandbox_flags_control); - virtual_browsing_context_group_ = std::move(virtual_browsing_context_group); - coep_reporter_ = std::move(coep_reporter); - coop_reporter_ = std::move(coop_reporter); - - // Store the required CSP (it will be used by the AncestorThrottle if - // this frame embeds a subframe when that subframe navigates). - required_csp_ = std::move(required_csp); - - if (coep_reporter_) { - mojo::PendingRemote<blink::mojom::ReportingObserver> remote; - mojo::PendingReceiver<blink::mojom::ReportingObserver> receiver = - remote.InitWithNewPipeAndPassReceiver(); - coep_reporter_->BindObserver(std::move(remote)); - // As some tests override the associated frame after commit, do not - // call GetAssociatedLocalFrame now. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(&RenderFrameHostImpl::BindReportingObserver, - weak_ptr_factory_.GetWeakPtr(), std::move(receiver))); - } - } - + // TODO(arthursonzogni): Recording the metrics again for same-document or + // bfcache navigation is a no-op. They were already recorded when the document + // committed. This should be moved toward NewDocumentCreatedFromNavigation(). RecordCrossOriginIsolationMetrics(this); + // TODO(arthursonzogni): Calling this for same-document navigation doesn't + // hurt, but this is useless. This should be executed only once per new + // document. This should be moved to CommitNewDocumentFromNavigation(). CrossOriginOpenerPolicyReporter::InstallAccessMonitorsIfNeeded( frame_tree_node_); return true; } +// TODO(arthursonzogni): Below, many NavigationRequest's objects are passed from +// the navigation to the new document. Consider grouping them in a single +// struct. +// +// TODO(arthursonzogni): Investigate what must be done when +// navigation_request->IsWaitingToCommit() is false here. +void RenderFrameHostImpl::DidCommitNewDocument( + const FrameHostMsg_DidCommitProvisionalLoad_Params& params, + NavigationRequest* navigation_request) { + // BackForwardCache navigations restore existing document, but never create + // new ones. + DCHECK(!navigation_request->IsServedFromBackForwardCache()); + + // After setting the last committed origin, reset the feature policy and + // sandbox flags in the RenderFrameHost to a blank policy based on the + // parent frame or opener frame. + ResetFeaturePolicy(); + active_sandbox_flags_ = frame_tree_node()->active_sandbox_flags(); + document_policy_ = blink::DocumentPolicy::CreateWithHeaderPolicy({}); + + // Since we're changing documents, we should reset the event handler + // trackers. + has_before_unload_handler_ = false; + has_unload_handler_ = false; + has_pagehide_handler_ = false; + has_visibilitychange_handler_ = false; + + DCHECK(params.embedding_token.has_value()); + SetEmbeddingToken(params.embedding_token.value()); + + renderer_reported_scheduler_tracked_features_ = 0; + browser_reported_scheduler_tracked_features_ = 0; + + last_committed_client_security_state_ = + navigation_request->TakeClientSecurityState(); + + cross_origin_opener_policy_ = + navigation_request->coop_status().current_coop(); + coop_reporter_ = navigation_request->coop_status().TakeCoopReporter(); + virtual_browsing_context_group_ = + navigation_request->coop_status().virtual_browsing_context_group(); + + // Store the required CSP (it will be used by the AncestorThrottle if + // this frame embeds a subframe when that subframe navigates). + required_csp_ = navigation_request->TakeRequiredCSP(); + + // Keep track of the sandbox policy of the document that has just committed. + // It will be compared with the value computed from the renderer. The latter + // is expected to be received in DidSetFramePolicyHeaders(..). + active_sandbox_flags_control_ = navigation_request->SandboxFlagsToCommit(); + + coep_reporter_ = navigation_request->TakeCoepReporter(); + if (coep_reporter_) { + mojo::PendingRemote<blink::mojom::ReportingObserver> remote; + mojo::PendingReceiver<blink::mojom::ReportingObserver> receiver = + remote.InitWithNewPipeAndPassReceiver(); + coep_reporter_->BindObserver(std::move(remote)); + // As some tests override the associated frame after commit, do not + // call GetAssociatedLocalFrame now. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&RenderFrameHostImpl::BindReportingObserver, + weak_ptr_factory_.GetWeakPtr(), std::move(receiver))); + } +} + void RenderFrameHostImpl::OnSameDocumentCommitProcessed( int64_t navigation_id, bool should_replace_current_entry,
diff --git a/content/browser/renderer_host/render_frame_host_impl.h b/content/browser/renderer_host/render_frame_host_impl.h index cea68d9..7076efe 100644 --- a/content/browser/renderer_host/render_frame_host_impl.h +++ b/content/browser/renderer_host/render_frame_host_impl.h
@@ -530,6 +530,7 @@ // true the navigation was not same-document and was not served from the // back-forward cache. void DidNavigate(const FrameHostMsg_DidCommitProvisionalLoad_Params& params, + NavigationRequest* navigation_request, bool did_create_new_document); AgentSchedulingGroupHost& agent_scheduling_group() { @@ -2363,6 +2364,12 @@ std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params, bool is_same_document_navigation); + // Called when we received the confirmation a new document committed in the + // renderer. It was created from the |navigation|. + void DidCommitNewDocument( + const FrameHostMsg_DidCommitProvisionalLoad_Params& params, + NavigationRequest* navigation); + // Called by the renderer process when it is done processing a same-document // commit request. void OnSameDocumentCommitProcessed(int64_t navigation_id,
diff --git a/content/browser/service_worker/service_worker_context_wrapper.cc b/content/browser/service_worker/service_worker_context_wrapper.cc index f63a930..4ba977c 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.cc +++ b/content/browser/service_worker/service_worker_context_wrapper.cc
@@ -572,7 +572,7 @@ } void ServiceWorkerContextWrapper::CountExternalRequestsForTest( - const GURL& origin, + const url::Origin& origin, CountExternalRequestsCallback callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); base::PostTask( @@ -1017,43 +1017,34 @@ void ServiceWorkerContextWrapper::FindReadyRegistrationForClientUrl( const GURL& client_url, FindRegistrationCallback callback) { - RunOrPostTaskOnCoreThread( - FROM_HERE, - base::BindOnce(&ServiceWorkerContextWrapper:: - FindReadyRegistrationForClientUrlOnCoreThread, - this, client_url, std::move(callback), - base::ThreadTaskRunnerHandle::Get())); -} - -void ServiceWorkerContextWrapper::FindReadyRegistrationForClientUrlOnCoreThread( - const GURL& client_url, - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); if (!context_core_) { - callback_runner->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - blink::ServiceWorkerStatusCode::kErrorAbort, nullptr)); + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, + nullptr); return; } context_core_->registry()->FindRegistrationForClientUrl( net::SimplifyUrlForRequest(client_url), base::BindOnce( - &ServiceWorkerContextWrapper::DidFindRegistrationForFindReady, this, - std::move(callback), std::move(callback_runner))); + &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, + /*include_installing_version=*/false, std::move(callback))); } void ServiceWorkerContextWrapper::FindReadyRegistrationForScope( const GURL& scope, FindRegistrationCallback callback) { + DCHECK_CURRENTLY_ON(GetCoreThreadId()); + if (!context_core_) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, + nullptr); + return; + } const bool include_installing_version = false; - RunOrPostTaskOnCoreThread( - FROM_HERE, + context_core_->registry()->FindRegistrationForScope( + net::SimplifyUrlForRequest(scope), base::BindOnce( - &ServiceWorkerContextWrapper::FindRegistrationForScopeOnCoreThread, - this, scope, include_installing_version, std::move(callback), - base::ThreadTaskRunnerHandle::Get())); + &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, + include_installing_version, std::move(callback))); } void ServiceWorkerContextWrapper::FindRegistrationForScope( @@ -1072,61 +1063,33 @@ int64_t registration_id, const url::Origin& origin, FindRegistrationCallback callback) { - RunOrPostTaskOnCoreThread( - FROM_HERE, - base::BindOnce( - &ServiceWorkerContextWrapper::FindReadyRegistrationForIdOnCoreThread, - this, registration_id, origin, std::move(callback), - base::ThreadTaskRunnerHandle::Get())); -} - -void ServiceWorkerContextWrapper::FindReadyRegistrationForIdOnCoreThread( - int64_t registration_id, - const url::Origin& origin, - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); if (!context_core_) { - callback_runner->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - blink::ServiceWorkerStatusCode::kErrorAbort, nullptr)); + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, + nullptr); return; } context_core_->registry()->FindRegistrationForId( registration_id, origin, base::BindOnce( - &ServiceWorkerContextWrapper::DidFindRegistrationForFindReady, this, - std::move(callback), std::move(callback_runner))); + &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, + /*include_installing_version=*/false, std::move(callback))); } void ServiceWorkerContextWrapper::FindReadyRegistrationForIdOnly( int64_t registration_id, FindRegistrationCallback callback) { - RunOrPostTaskOnCoreThread( - FROM_HERE, base::BindOnce(&ServiceWorkerContextWrapper:: - FindReadyRegistrationForIdOnlyOnCoreThread, - this, registration_id, std::move(callback), - base::ThreadTaskRunnerHandle::Get())); -} - -void ServiceWorkerContextWrapper::FindReadyRegistrationForIdOnlyOnCoreThread( - int64_t registration_id, - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); if (!context_core_) { - callback_runner->PostTask( - FROM_HERE, - base::BindOnce(std::move(callback), - blink::ServiceWorkerStatusCode::kErrorAbort, nullptr)); + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorAbort, + nullptr); return; } context_core_->registry()->FindRegistrationForIdOnly( registration_id, base::BindOnce( - &ServiceWorkerContextWrapper::DidFindRegistrationForFindReady, this, - std::move(callback), std::move(callback_runner))); + &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, + /*include_installing_version=*/false, std::move(callback))); } void ServiceWorkerContextWrapper::GetAllRegistrations( @@ -1652,10 +1615,10 @@ } context_core_->registry()->FindRegistrationForScope( net::SimplifyUrlForRequest(scope), - base::BindOnce( - &ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl, this, - include_installing_version, std::move(callback), - std::move(callback_runner))); + base::BindOnce(&ServiceWorkerContextWrapper:: + DidFindRegistrationForFindImplWithRunner, + this, include_installing_version, std::move(callback), + std::move(callback_runner))); } void ServiceWorkerContextWrapper::ShutdownOnCoreThread() { @@ -1665,7 +1628,7 @@ context_core_.reset(); } -void ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl( +void ServiceWorkerContextWrapper::DidFindRegistrationForFindImplWithRunner( bool include_installing_version, FindRegistrationCallback callback, scoped_refptr<base::TaskRunner> callback_runner, @@ -1688,10 +1651,11 @@ if (active_version) { if (active_version->status() == ServiceWorkerVersion::ACTIVATING) { // Wait until the version is activated. - active_version->RegisterStatusChangeCallback(base::BindOnce( - &ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration, - this, std::move(callback), std::move(callback_runner), - std::move(registration))); + active_version->RegisterStatusChangeCallback( + base::BindOnce(&ServiceWorkerContextWrapper:: + OnStatusChangedForFindReadyRegistrationWithRunner, + this, std::move(callback), std::move(callback_runner), + std::move(registration))); return; } DCHECK_EQ(ServiceWorkerVersion::ACTIVATED, active_version->status()); @@ -1716,21 +1680,53 @@ blink::ServiceWorkerStatusCode::kErrorNotFound, nullptr)); } -void ServiceWorkerContextWrapper::DidFindRegistrationForFindReady( +void ServiceWorkerContextWrapper::DidFindRegistrationForFindImpl( + bool include_installing_version, FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner, blink::ServiceWorkerStatusCode status, scoped_refptr<ServiceWorkerRegistration> registration) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); - DidFindRegistrationForFindImpl( - false /* include_installing_version */, std::move(callback), - std::move(callback_runner), status, std::move(registration)); + if (status != blink::ServiceWorkerStatusCode::kOk) { + std::move(callback).Run(status, nullptr); + return; + } + + // Attempt to activate the waiting version because the registration retrieved + // from the disk might have only the waiting version. + if (registration->waiting_version()) + registration->ActivateWaitingVersionWhenReady(); + + scoped_refptr<ServiceWorkerVersion> active_version = + registration->active_version(); + if (active_version) { + if (active_version->status() == ServiceWorkerVersion::ACTIVATING) { + // Wait until the version is activated. + active_version->RegisterStatusChangeCallback(base::BindOnce( + &ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration, + this, std::move(callback), std::move(registration))); + return; + } + DCHECK_EQ(ServiceWorkerVersion::ACTIVATED, active_version->status()); + std::move(callback).Run(blink::ServiceWorkerStatusCode::kOk, + std::move(registration)); + return; + } + + if (include_installing_version && registration->installing_version()) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kOk, + std::move(registration)); + return; + } + + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorNotFound, + nullptr); } -void ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration( - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner, - scoped_refptr<ServiceWorkerRegistration> registration) { +void ServiceWorkerContextWrapper:: + OnStatusChangedForFindReadyRegistrationWithRunner( + FindRegistrationCallback callback, + scoped_refptr<base::TaskRunner> callback_runner, + scoped_refptr<ServiceWorkerRegistration> registration) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); scoped_refptr<ServiceWorkerVersion> active_version = registration->active_version(); @@ -1749,6 +1745,21 @@ registration)); } +void ServiceWorkerContextWrapper::OnStatusChangedForFindReadyRegistration( + FindRegistrationCallback callback, + scoped_refptr<ServiceWorkerRegistration> registration) { + DCHECK_CURRENTLY_ON(GetCoreThreadId()); + scoped_refptr<ServiceWorkerVersion> active_version = + registration->active_version(); + if (!active_version || + active_version->status() != ServiceWorkerVersion::ACTIVATED) { + std::move(callback).Run(blink::ServiceWorkerStatusCode::kErrorNotFound, + nullptr); + return; + } + std::move(callback).Run(blink::ServiceWorkerStatusCode::kOk, registration); +} + void ServiceWorkerContextWrapper::DidDeleteAndStartOver( blink::ServiceWorkerStatusCode status) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); @@ -1833,7 +1844,7 @@ } void ServiceWorkerContextWrapper::CountExternalRequests( - const GURL& origin, + const url::Origin& origin, CountExternalRequestsCallback callback) { DCHECK_CURRENTLY_ON(GetCoreThreadId()); @@ -1842,7 +1853,7 @@ size_t pending_external_request_count = 0; for (const ServiceWorkerVersionInfo& info : live_version_info) { ServiceWorkerVersion* version = GetLiveVersion(info.version_id); - if (version && version->scope().GetOrigin() == origin) { + if (version && version->origin() == origin) { pending_external_request_count = version->GetExternalRequestCountForTest(); break;
diff --git a/content/browser/service_worker/service_worker_context_wrapper.h b/content/browser/service_worker/service_worker_context_wrapper.h index 1fb22fda..d91f6d9b 100644 --- a/content/browser/service_worker/service_worker_context_wrapper.h +++ b/content/browser/service_worker/service_worker_context_wrapper.h
@@ -171,7 +171,7 @@ int64_t service_worker_version_id, const std::string& request_uuid) override; void CountExternalRequestsForTest( - const GURL& url, + const url::Origin& origin, CountExternalRequestsCallback callback) override; bool MaybeHasRegistrationForOrigin(const url::Origin& origin) override; void GetInstalledRegistrationOrigins( @@ -227,7 +227,9 @@ // version, activates the waiting version and runs |callback| when it is // activated. // - // Can be called on any thread, and the callback is called on that thread. + // Must be called on the core thread, and |callback| is called on that thread. + // There is no guarantee for whether the callback is called synchronously or + // asynchronously. void FindReadyRegistrationForClientUrl(const GURL& client_url, FindRegistrationCallback callback); @@ -241,7 +243,9 @@ // version, activates the waiting version and runs |callback| when it is // activated. // - // Can be called from any thread, and the callback is called on that thread. + // Must be called on the core thread, and |callback| is called on that thread. + // There is no guarantee for whether the callback is called synchronously or + // asynchronously. void FindReadyRegistrationForScope(const GURL& scope, FindRegistrationCallback callback); @@ -261,7 +265,9 @@ // version, activates the waiting version and runs |callback| when it is // activated. // - // Can be called from any thread, and the callback is called on that thread. + // Must be called on the core thread, and the callback is called on that + // thread. There is no guarantee about whether the callback is called + // asynchronously or synchronously. void FindReadyRegistrationForId(int64_t registration_id, const url::Origin& origin, FindRegistrationCallback callback); @@ -280,7 +286,9 @@ // version, activates the waiting version and runs |callback| when it is // activated. // - // Can be called from any thread, and the callback is called on that thread. + // Must be called on the core thread, and the callback is called on that + // thread. There is no guarantee about whether the callback is called + // synchronously or asynchronously. void FindReadyRegistrationForIdOnly(int64_t registration_id, FindRegistrationCallback callback); @@ -402,7 +410,11 @@ bool include_installing_version, FindRegistrationCallback callback); - void DidFindRegistrationForFindReady( + // TODO(crbug.com/1127724): The *WithRunner functions should be removed. + // FindRegistrationCallback should only be called on the core thread, since + // ServiceWorkerRegistration is bound to that thread. + void DidFindRegistrationForFindImplWithRunner( + bool include_installing_version, FindRegistrationCallback callback, scoped_refptr<base::TaskRunner> callback_runner, blink::ServiceWorkerStatusCode status, @@ -410,12 +422,14 @@ void DidFindRegistrationForFindImpl( bool include_installing_version, FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner, blink::ServiceWorkerStatusCode status, scoped_refptr<ServiceWorkerRegistration> registration); + void OnStatusChangedForFindReadyRegistrationWithRunner( + FindRegistrationCallback callback, + scoped_refptr<base::TaskRunner> callback_runner, + scoped_refptr<ServiceWorkerRegistration> registration); void OnStatusChangedForFindReadyRegistration( FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner, scoped_refptr<ServiceWorkerRegistration> registration); void DidDeleteAndStartOver(blink::ServiceWorkerStatusCode status); @@ -436,7 +450,7 @@ blink::ServiceWorkerStatusCode status, scoped_refptr<content::ServiceWorkerRegistration> registration); - void CountExternalRequests(const GURL& url, + void CountExternalRequests(const url::Origin& origin, CountExternalRequestsCallback callback); void DidFindRegistrationForNavigationHint( @@ -514,15 +528,6 @@ blink::TransferableMessage message, ResultCallback result_callback, scoped_refptr<base::TaskRunner> callback_runner); - void FindReadyRegistrationForIdOnCoreThread( - int64_t registration_id, - const url::Origin& origin, - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner); - void FindReadyRegistrationForIdOnlyOnCoreThread( - int64_t registration_id, - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner); void DeleteForOriginOnCoreThread( const url::Origin& origin, ResultCallback callback, @@ -536,10 +541,6 @@ const GURL& origin, BoolCallback callback, scoped_refptr<base::TaskRunner> callback_runner) const; - void FindReadyRegistrationForClientUrlOnCoreThread( - const GURL& client_url, - FindRegistrationCallback callback, - scoped_refptr<base::TaskRunner> callback_runner); void GetAllRegistrationsOnCoreThread(GetRegistrationsInfosCallback callback); void GetRegistrationUserDataOnCoreThread(int64_t registration_id, const std::vector<std::string>& keys,
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index 4ab086f..736ce2c 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -4164,7 +4164,11 @@ csp_values[i].c_str()))); NavigateFrameToURL(child, urls[i]); - EXPECT_EQ(csp_values[i], child->frame_owner_properties().required_csp); + if (!base::FeatureList::IsEnabled(network::features::kOutOfBlinkCSPEE)) { + EXPECT_EQ(csp_values[i], child->frame_owner_properties().required_csp); + } else { + EXPECT_EQ(csp_values[i], child->csp_attribute()->header->header_value); + } // TODO(amalika): add checks that the CSP replication takes effect const url::Origin child_origin =
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom index 6214996..5515b7cf 100644 --- a/content/common/renderer.mojom +++ b/content/common/renderer.mojom
@@ -260,12 +260,24 @@ // Tells the renderer to create a new AgentSchedulingGroup, that will // communicate via the pending |agent_scheduling_group_host| and - // |agent_scheduling_group|. + // |agent_scheduling_group|. This will create "independent" interfaces that + // are not associated with the IPC channel, which will not guarantee any order + // across agent scheduling groups. CreateAgentSchedulingGroup( pending_remote<AgentSchedulingGroupHost> agent_scheduling_group_host, pending_receiver<AgentSchedulingGroup> agent_scheduling_group ); + // Tells the renderer to create a new AgentSchedulingGroup, that will + // communicate via the pending |agent_scheduling_group_host| and + // |agent_scheduling_group|. This will create channel-associated interfaces + // that will preserve message ordering across agent scheduling groups. + CreateAssociatedAgentSchedulingGroup( + pending_associated_remote<AgentSchedulingGroupHost> + agent_scheduling_group_host, + pending_associated_receiver<AgentSchedulingGroup> agent_scheduling_group + ); + // Tells the renderer to create a new RenderFrameProxy object with // |routing_id|. |render_view_routing_id| identifies the // RenderView to be associated with this proxy. The new proxy's opener should
diff --git a/content/public/browser/service_worker_context.h b/content/public/browser/service_worker_context.h index a377246c..aa6bfab 100644 --- a/content/public/browser/service_worker_context.h +++ b/content/public/browser/service_worker_context.h
@@ -157,7 +157,7 @@ // specified |origin| via |callback|. Must be called from the UI thread. The // callback is called on the UI thread. virtual void CountExternalRequestsForTest( - const GURL& origin, + const url::Origin& origin, CountExternalRequestsCallback callback) = 0; // Whether |origin| has any registrations. Uninstalling and uninstalled
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 15e7031..fec6ac1 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -349,6 +349,14 @@ const base::Feature kLowPriorityIframes{"LowPriorityIframes", base::FEATURE_DISABLED_BY_DEFAULT}; +// Removes the association between the `AgentSchedulingGroup` interfaces and the +// IPC Channel. This will break ordering guarantees between different agent +// scheduling groups (ordering withing a group is still preserved). +// DO NOT USE! The feature is not yet fully implemented. See crbug.com/1111231. +const base::Feature kMbiDetachAgentSchedulingGroupFromChannel{ + "MbiDetachAgentSchedulingGroupFromChannel", + base::FEATURE_DISABLED_BY_DEFAULT}; + // If this feature is enabled, media-device enumerations use a cache that is // invalidated upon notifications sent by base::SystemMonitor. If disabled, the // cache is considered invalid on every enumeration request. @@ -567,7 +575,7 @@ // IO thread. // https://crbug.com/824858 const base::Feature kServiceWorkerOnUI{"ServiceWorkerOnUI", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Service worker based payment apps as defined by w3c here: // https://w3c.github.io/webpayments-payment-apps-api/
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 16661b83..85de294 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -82,6 +82,8 @@ CONTENT_EXPORT extern const base::Feature kLegacyWindowsDWriteFontFallback; CONTENT_EXPORT extern const base::Feature kLogJsConsoleMessages; CONTENT_EXPORT extern const base::Feature kLowPriorityIframes; +CONTENT_EXPORT extern const base::Feature + kMbiDetachAgentSchedulingGroupFromChannel; CONTENT_EXPORT extern const base::Feature kMediaDevicesSystemMonitorCache; CONTENT_EXPORT extern const base::Feature kMojoDedicatedThread; CONTENT_EXPORT extern const base::Feature kMojoVideoCapture;
diff --git a/content/public/test/fake_service_worker_context.cc b/content/public/test/fake_service_worker_context.cc index cb412e3..27c4d0b 100644 --- a/content/public/test/fake_service_worker_context.cc +++ b/content/public/test/fake_service_worker_context.cc
@@ -51,7 +51,7 @@ return ServiceWorkerExternalRequestResult::kWorkerNotFound; } void FakeServiceWorkerContext::CountExternalRequestsForTest( - const GURL& url, + const url::Origin& origin, CountExternalRequestsCallback callback) { NOTREACHED(); }
diff --git a/content/public/test/fake_service_worker_context.h b/content/public/test/fake_service_worker_context.h index dae099f89..41d4ddd 100644 --- a/content/public/test/fake_service_worker_context.h +++ b/content/public/test/fake_service_worker_context.h
@@ -46,7 +46,7 @@ int64_t service_worker_version_id, const std::string& request_uuid) override; void CountExternalRequestsForTest( - const GURL& url, + const url::Origin& origin, CountExternalRequestsCallback callback) override; bool MaybeHasRegistrationForOrigin(const url::Origin& origin) override; void GetInstalledRegistrationOrigins(
diff --git a/content/renderer/agent_scheduling_group.cc b/content/renderer/agent_scheduling_group.cc index 47dd82d..e78d6fa 100644 --- a/content/renderer/agent_scheduling_group.cc +++ b/content/renderer/agent_scheduling_group.cc
@@ -4,19 +4,92 @@ #include "content/renderer/agent_scheduling_group.h" +#include "base/feature_list.h" +#include "content/public/common/content_features.h" + namespace content { +using ::mojo::AssociatedReceiver; +using ::mojo::AssociatedRemote; +using ::mojo::PendingAssociatedReceiver; +using ::mojo::PendingAssociatedRemote; +using ::mojo::PendingReceiver; +using ::mojo::PendingRemote; +using ::mojo::Receiver; +using ::mojo::Remote; + +// MaybeAssociatedReceiver: +AgentSchedulingGroup::MaybeAssociatedReceiver::MaybeAssociatedReceiver( + AgentSchedulingGroup& impl, + PendingReceiver<mojom::AgentSchedulingGroup> receiver, + base::OnceClosure disconnect_handler) + : receiver_(absl::in_place_type<Receiver<mojom::AgentSchedulingGroup>>, + &impl, + std::move(receiver)) { + if (disconnect_handler) + absl::get<Receiver<mojom::AgentSchedulingGroup>>(receiver_) + .set_disconnect_handler(std::move(disconnect_handler)); +} + +AgentSchedulingGroup::MaybeAssociatedReceiver::MaybeAssociatedReceiver( + AgentSchedulingGroup& impl, + PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver, + base::OnceClosure disconnect_handler) + : receiver_( + absl::in_place_type<AssociatedReceiver<mojom::AgentSchedulingGroup>>, + &impl, + std::move(receiver)) { + if (disconnect_handler) + absl::get<AssociatedReceiver<mojom::AgentSchedulingGroup>>(receiver_) + .set_disconnect_handler(std::move(disconnect_handler)); +} + +AgentSchedulingGroup::MaybeAssociatedReceiver::~MaybeAssociatedReceiver() = + default; + +// MaybeAssociatedRemote: +AgentSchedulingGroup::MaybeAssociatedRemote::MaybeAssociatedRemote( + PendingRemote<mojom::AgentSchedulingGroupHost> host_remote) + : remote_(absl::in_place_type<Remote<mojom::AgentSchedulingGroupHost>>, + std::move(host_remote)) {} + +AgentSchedulingGroup::MaybeAssociatedRemote::MaybeAssociatedRemote( + PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> host_remote) + : remote_(absl::in_place_type< + AssociatedRemote<mojom::AgentSchedulingGroupHost>>, + std::move(host_remote)) {} + +AgentSchedulingGroup::MaybeAssociatedRemote::~MaybeAssociatedRemote() = default; + +// AgentSchedulingGroup: AgentSchedulingGroup::AgentSchedulingGroup( - mojo::PendingRemote<mojom::AgentSchedulingGroupHost> host_remote, - mojo::PendingReceiver<mojom::AgentSchedulingGroup> receiver, + PendingRemote<mojom::AgentSchedulingGroupHost> host_remote, + PendingReceiver<mojom::AgentSchedulingGroup> receiver, base::OnceCallback<void(const AgentSchedulingGroup*)> mojo_disconnect_handler) // TODO(crbug.com/1111231): Mojo interfaces should be associated with // per-ASG task runners instead of default. - : receiver_(this, std::move(receiver)), + : receiver_(*this, + std::move(receiver), + base::BindOnce(std::move(mojo_disconnect_handler), this)), host_remote_(std::move(host_remote)) { - receiver_.set_disconnect_handler( - base::BindOnce(std::move(mojo_disconnect_handler), this)); + DCHECK(base::FeatureList::IsEnabled( + features::kMbiDetachAgentSchedulingGroupFromChannel)); +} + +AgentSchedulingGroup::AgentSchedulingGroup( + PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> host_remote, + PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver, + base::OnceCallback<void(const AgentSchedulingGroup*)> + mojo_disconnect_handler) + // TODO(crbug.com/1111231): Mojo interfaces should be associated with + // per-ASG task runners instead of default. + : receiver_(*this, + std::move(receiver), + base::BindOnce(std::move(mojo_disconnect_handler), this)), + host_remote_(std::move(host_remote)) { + DCHECK(!base::FeatureList::IsEnabled( + features::kMbiDetachAgentSchedulingGroupFromChannel)); } AgentSchedulingGroup::~AgentSchedulingGroup() = default;
diff --git a/content/renderer/agent_scheduling_group.h b/content/renderer/agent_scheduling_group.h index a0d9d73..b0ba2ee0 100644 --- a/content/renderer/agent_scheduling_group.h +++ b/content/renderer/agent_scheduling_group.h
@@ -8,8 +8,11 @@ #include "base/callback.h" #include "content/common/agent_scheduling_group.mojom.h" #include "content/common/content_export.h" +#include "mojo/public/cpp/bindings/associated_receiver.h" +#include "mojo/public/cpp/bindings/associated_remote.h" #include "mojo/public/cpp/bindings/receiver.h" #include "mojo/public/cpp/bindings/remote.h" +#include "third_party/abseil-cpp/absl/types/variant.h" namespace content { @@ -27,6 +30,12 @@ mojo::PendingReceiver<mojom::AgentSchedulingGroup> receiver, base::OnceCallback<void(const AgentSchedulingGroup*)> mojo_disconnect_handler); + AgentSchedulingGroup( + mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> + host_remote, + mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver, + base::OnceCallback<void(const AgentSchedulingGroup*)> + mojo_disconnect_handler); ~AgentSchedulingGroup() override; AgentSchedulingGroup(const AgentSchedulingGroup&) = delete; @@ -35,13 +44,55 @@ AgentSchedulingGroup& operator=(const AgentSchedulingGroup&&) = delete; private: + // `MaybeAssociatedReceiver` and `MaybeAssociatedRemote` are temporary helper + // classes that allow us to switch between using associated and non-associated + // mojo interfaces. This behavior is controlled by the + // `kMbiDetachAgentSchedulingGroupFromChannel` feature flag. + // Associated interfaces are associated with the IPC channel (transitively, + // via the `Renderer` interface), thus preserving cross-agent scheduling group + // message order. Non-associated interfaces are independent from each other + // and do not preserve message order between agent scheduling groups. + // TODO(crbug.com/1111231): Remove these once we can remove the flag. + class MaybeAssociatedReceiver { + public: + MaybeAssociatedReceiver( + AgentSchedulingGroup& impl, + mojo::PendingReceiver<mojom::AgentSchedulingGroup> receiver, + base::OnceClosure disconnect_handler); + MaybeAssociatedReceiver( + AgentSchedulingGroup& impl, + mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> receiver, + base::OnceClosure disconnect_handler); + ~MaybeAssociatedReceiver(); + + private: + absl::variant<mojo::Receiver<mojom::AgentSchedulingGroup>, + mojo::AssociatedReceiver<mojom::AgentSchedulingGroup>> + receiver_; + }; + + class MaybeAssociatedRemote { + public: + explicit MaybeAssociatedRemote( + mojo::PendingRemote<mojom::AgentSchedulingGroupHost> host_remote); + explicit MaybeAssociatedRemote( + mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> + host_remote); + ~MaybeAssociatedRemote(); + + private: + absl::variant<mojo::Remote<mojom::AgentSchedulingGroupHost>, + mojo::AssociatedRemote<mojom::AgentSchedulingGroupHost>> + remote_; + }; + // Implementation of `mojom::AgentSchedulingGroup`, used for responding to // calls from the (browser-side) `AgentSchedulingGroupHost`. - mojo::Receiver<mojom::AgentSchedulingGroup> receiver_; + MaybeAssociatedReceiver receiver_; // Remote stub of mojom::AgentSchedulingGroupHost, used for sending calls to // the (browser-side) AgentSchedulingGroupHost. - mojo::Remote<mojom::AgentSchedulingGroupHost> host_remote_; + MaybeAssociatedRemote host_remote_; }; } // namespace content
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index 00fa473..b5d51f30a 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -1875,6 +1875,16 @@ remove_agent_scheduling_group_callback_)); } +void RenderThreadImpl::CreateAssociatedAgentSchedulingGroup( + mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> + agent_scheduling_group_host, + mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> + agent_scheduling_group) { + agent_scheduling_groups_.emplace(std::make_unique<AgentSchedulingGroup>( + std::move(agent_scheduling_group_host), std::move(agent_scheduling_group), + remove_agent_scheduling_group_callback_)); +} + void RenderThreadImpl::CreateFrameProxy( int32_t routing_id, int32_t render_view_routing_id,
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h index 7f4146f8..f84be80 100644 --- a/content/renderer/render_thread_impl.h +++ b/content/renderer/render_thread_impl.h
@@ -448,6 +448,11 @@ agent_scheduling_group_host, mojo::PendingReceiver<mojom::AgentSchedulingGroup> agent_scheduling_group) override; + void CreateAssociatedAgentSchedulingGroup( + mojo::PendingAssociatedRemote<mojom::AgentSchedulingGroupHost> + agent_scheduling_group_host, + mojo::PendingAssociatedReceiver<mojom::AgentSchedulingGroup> + agent_scheduling_group) override; void CreateFrameProxy( int32_t routing_id, int32_t render_view_routing_id,
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.cc b/gpu/command_buffer/service/shared_image_backing_egl_image.cc index 498550e..62dca6c 100644 --- a/gpu/command_buffer/service/shared_image_backing_egl_image.cc +++ b/gpu/command_buffer/service/shared_image_backing_egl_image.cc
@@ -17,25 +17,43 @@ namespace gpu { +class SharedImageBackingEglImage::TextureHolder + : public base::RefCounted<TextureHolder> { + public: + TextureHolder(gles2::Texture* texture) : texture_(texture) {} + + void MarkContextLost() { context_lost_ = true; } + + gles2::Texture* texture() { return texture_; } + + private: + friend class base::RefCounted<TextureHolder>; + + ~TextureHolder() { texture_->RemoveLightweightRef(!context_lost_); } + + gles2::Texture* const texture_; + bool context_lost_ = false; +}; + // Implementation of SharedImageRepresentationGLTexture which uses GL texture // which is an EGLImage sibling. class SharedImageRepresentationEglImageGLTexture : public SharedImageRepresentationGLTexture { public: - SharedImageRepresentationEglImageGLTexture(SharedImageManager* manager, - SharedImageBacking* backing, - MemoryTypeTracker* tracker, - gles2::Texture* texture, - bool should_delete_texture) + using TextureHolder = SharedImageBackingEglImage::TextureHolder; + SharedImageRepresentationEglImageGLTexture( + SharedImageManager* manager, + SharedImageBacking* backing, + MemoryTypeTracker* tracker, + scoped_refptr<TextureHolder> texture_holder) : SharedImageRepresentationGLTexture(manager, backing, tracker), - texture_(texture), - should_delete_texture_(should_delete_texture) {} + texture_holder_(std::move(texture_holder)) {} ~SharedImageRepresentationEglImageGLTexture() override { EndAccess(); - - if (texture_ && should_delete_texture_) - texture_->RemoveLightweightRef(has_context()); + if (!has_context()) + texture_holder_->MarkContextLost(); + texture_holder_.reset(); } bool BeginAccess(GLenum mode) override { @@ -69,7 +87,7 @@ mode_ = RepresentationAccessMode::kNone; } - gles2::Texture* GetTexture() override { return texture_; } + gles2::Texture* GetTexture() override { return texture_holder_->texture(); } bool SupportsMultipleConcurrentReadAccess() override { return true; } @@ -78,8 +96,7 @@ return static_cast<SharedImageBackingEglImage*>(backing()); } - gles2::Texture* texture_; - const bool should_delete_texture_; + scoped_refptr<TextureHolder> texture_holder_; RepresentationAccessMode mode_ = RepresentationAccessMode::kNone; DISALLOW_COPY_AND_ASSIGN(SharedImageRepresentationEglImageGLTexture); }; @@ -114,14 +131,16 @@ // On some GPUs (NVidia) keeping reference to egl image itself is not enough, // we must keep reference to at least one sibling. if (workarounds.dont_delete_source_texture_for_egl_image) { - source_texture_ = GenEGLImageSibling(); + auto* texture = GenEGLImageSibling(); + if (texture) + source_texture_holder_ = base::MakeRefCounted<TextureHolder>(texture); } } SharedImageBackingEglImage::~SharedImageBackingEglImage() { // Un-Register this backing from the |batch_access_manager_|. batch_access_manager_->UnregisterEglBacking(this); - DCHECK(!source_texture_); + DCHECK(!source_texture_holder_); } void SharedImageBackingEglImage::Update( @@ -141,17 +160,21 @@ // On some GPUs (Mali, mostly Android 9, like J7) glTexSubImage fails on egl // image sibling. So we use the original texture if we're on the same gl // context. see https://crbug.com/1117370 - if (source_texture_ && created_on_context_ == gl::g_current_gl_context) { + // If we're on the same context we're on the same thread, so + // source_texture_holder_ is accessed only from thread we created it and + // doesn't need lock. + if (created_on_context_ == gl::g_current_gl_context && + source_texture_holder_) { return std::make_unique<SharedImageRepresentationEglImageGLTexture>( - manager, this, tracker, source_texture_, - /*should_delete_texture=*/false); + manager, this, tracker, source_texture_holder_); } auto* texture = GenEGLImageSibling(); if (!texture) return nullptr; + auto texture_holder = base::MakeRefCounted<TextureHolder>(texture); return std::make_unique<SharedImageRepresentationEglImageGLTexture>( - manager, this, tracker, texture, /*should_delete_texture=*/true); + manager, this, tracker, std::move(texture_holder)); } std::unique_ptr<SharedImageRepresentationSkia> @@ -332,10 +355,9 @@ AutoLock auto_lock(this); DCHECK(!have_context() || created_on_context_ == gl::g_current_gl_context); - if (source_texture_) { - source_texture_->RemoveLightweightRef(have_context()); - source_texture_ = nullptr; - } + if (!have_context()) + source_texture_holder_->MarkContextLost(); + source_texture_holder_.reset(); } } // namespace gpu
diff --git a/gpu/command_buffer/service/shared_image_backing_egl_image.h b/gpu/command_buffer/service/shared_image_backing_egl_image.h index fc910f0..626d51b 100644 --- a/gpu/command_buffer/service/shared_image_backing_egl_image.h +++ b/gpu/command_buffer/service/shared_image_backing_egl_image.h
@@ -73,6 +73,7 @@ private: friend class SharedImageBatchAccessManager; friend class SharedImageRepresentationEglImageGLTexture; + class TextureHolder; // Use to create EGLImage texture target from the same EGLImage object. gles2::Texture* GenEGLImageSibling(); @@ -81,7 +82,7 @@ const GLuint gl_format_; const GLuint gl_type_; - gles2::Texture* source_texture_ = nullptr; + scoped_refptr<TextureHolder> source_texture_holder_; gl::GLApi* created_on_context_; // This class encapsulates the EGLImage object for android.
diff --git a/ios/build/chrome_build.gni b/ios/build/chrome_build.gni index 2ebd9fc..d55002a 100644 --- a/ios/build/chrome_build.gni +++ b/ios/build/chrome_build.gni
@@ -27,7 +27,7 @@ # Enable multi-window configuration in Info.plist. Includes all the effects of # setting |ios_enable_scene_startup| to |true|. - ios_enable_multi_window = false + ios_enable_multi_window = true # Value of the encryption export compliance code. See "Cryptography and # U.S. Export Compliance" in "Submitting the App to App Review" in the
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn index f12e080..8245b82 100644 --- a/ios/chrome/browser/tabs/BUILD.gn +++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -48,10 +48,7 @@ "//components/favicon/ios", "//components/history/core/browser", "//components/history/ios/browser", - "//components/keyed_service/core", "//components/language/ios/browser", - "//components/navigation_metrics", - "//components/profile_metrics", "//components/safe_browsing/core:features", "//components/safe_browsing/ios/browser:allow_list", "//components/security_state/ios", @@ -61,16 +58,13 @@ "//ios/chrome/browser/autofill", "//ios/chrome/browser/autofill:autofill_internal", "//ios/chrome/browser/browser_state", - "//ios/chrome/browser/browser_state_metrics", "//ios/chrome/browser/complex_tasks", - "//ios/chrome/browser/crash_report", "//ios/chrome/browser/crash_report/breadcrumbs", "//ios/chrome/browser/crash_report/breadcrumbs:feature_flags", "//ios/chrome/browser/download", "//ios/chrome/browser/favicon", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/geolocation", - "//ios/chrome/browser/geolocation:geolocation_internal", "//ios/chrome/browser/history", "//ios/chrome/browser/history:tab_helper", "//ios/chrome/browser/infobars", @@ -86,14 +80,11 @@ "//ios/chrome/browser/passwords", "//ios/chrome/browser/policy:feature_flags", "//ios/chrome/browser/policy_url_blocking", - "//ios/chrome/browser/prerender", "//ios/chrome/browser/reading_list", "//ios/chrome/browser/safe_browsing", "//ios/chrome/browser/search_engines", "//ios/chrome/browser/sessions", "//ios/chrome/browser/sessions:restoration_agent", - "//ios/chrome/browser/sessions:serialisation", - "//ios/chrome/browser/sessions:session_service", "//ios/chrome/browser/snapshots", "//ios/chrome/browser/ssl", "//ios/chrome/browser/store_kit", @@ -105,7 +96,6 @@ "//ios/chrome/browser/voice", "//ios/chrome/browser/web", "//ios/chrome/browser/web:feature_flags", - "//ios/chrome/browser/web:java_script_console", "//ios/chrome/browser/web:page_placeholder", "//ios/chrome/browser/web:web_internal", "//ios/chrome/browser/web_state_list",
diff --git a/ios/chrome/browser/tabs/tab_model.mm b/ios/chrome/browser/tabs/tab_model.mm index 6e2128f..4d14112 100644 --- a/ios/chrome/browser/tabs/tab_model.mm +++ b/ios/chrome/browser/tabs/tab_model.mm
@@ -4,52 +4,19 @@ #import "ios/chrome/browser/tabs/tab_model.h" -#include <cstdint> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/callback_helpers.h" -#include "base/check_op.h" -#import "base/mac/foundation_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/user_metrics_action.h" -#include "base/notreached.h" -#include "base/stl_util.h" -#include "base/strings/sys_string_conversions.h" #include "base/task/cancelable_task_tracker.h" #include "base/task/post_task.h" -#include "components/navigation_metrics/navigation_metrics.h" -#include "components/profile_metrics/browser_profile_type.h" -#include "components/sessions/core/tab_restore_service.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#include "ios/chrome/browser/browser_state_metrics/browser_state_metrics.h" -#include "ios/chrome/browser/chrome_url_constants.h" -#import "ios/chrome/browser/chrome_url_util.h" -#include "ios/chrome/browser/crash_report/crash_loop_detection_util.h" -#import "ios/chrome/browser/geolocation/omnibox_geolocation_controller.h" -#include "ios/chrome/browser/main/browser.h" -#import "ios/chrome/browser/main/browser_web_state_list_delegate.h" -#import "ios/chrome/browser/prerender/prerender_service_factory.h" -#include "ios/chrome/browser/sessions/ios_chrome_tab_restore_service_factory.h" #import "ios/chrome/browser/sessions/session_restoration_browser_agent.h" -#import "ios/chrome/browser/sessions/session_service_ios.h" -#import "ios/chrome/browser/sessions/session_window_ios.h" #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h" #import "ios/chrome/browser/tabs/tab_parenting_observer.h" #import "ios/chrome/browser/web_state_list/web_state_list.h" -#import "ios/chrome/browser/web_state_list/web_state_list_observer.h" #import "ios/chrome/browser/web_state_list/web_usage_enabler/web_usage_enabler_browser_agent.h" -#include "ios/web/public/browser_state.h" -#import "ios/web/public/navigation/navigation_context.h" -#include "ios/web/public/navigation/navigation_item.h" -#import "ios/web/public/navigation/navigation_manager.h" #include "ios/web/public/security/certificate_policy_cache.h" #include "ios/web/public/session/session_certificate_policy_cache.h" #include "ios/web/public/thread/web_task_traits.h" #include "ios/web/public/thread/web_thread.h" #import "ios/web/public/web_state_observer_bridge.h" -#include "url/gurl.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support."
diff --git a/ios/chrome/browser/ui/popup_menu/public/popup_menu_presenter.mm b/ios/chrome/browser/ui/popup_menu/public/popup_menu_presenter.mm index 176e9c8..0a685c04 100644 --- a/ios/chrome/browser/ui/popup_menu/public/popup_menu_presenter.mm +++ b/ios/chrome/browser/ui/popup_menu/public/popup_menu_presenter.mm
@@ -150,6 +150,10 @@ - (void)dismissAnimated:(BOOL)animated { [self.popupViewController willMoveToParentViewController:nil]; + // Notify the presented view controller that it will be removed to prevent it + // from triggering unnecessary layout passes, which might lead to a hang. See + // crbug.com/1126618. + [self.presentedViewController willMoveToParentViewController:nil]; [NSLayoutConstraint deactivateConstraints:self.presentedConstraints]; [NSLayoutConstraint activateConstraints:self.initialConstraints]; auto completion = ^(BOOL finished) {
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.h b/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.h index b336d04f..f3783e5 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.h +++ b/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.h
@@ -15,6 +15,42 @@ #include "media/capture/video/video_capture_device.h" #include "media/capture/video_capture_types.h" +namespace media { +class VideoCaptureDeviceMac; +} + +// Class used by VideoCaptureDeviceMac (VCDM) for video and image capture using +// AVFoundation API. This class lives inside the thread created by its owner +// VCDM. +// +// * Clients (VCDM) should call +deviceNames to fetch the list of devices +// available in the system; this method returns the list of device names that +// have to be used with -setCaptureDevice:. +// * Previous to any use, clients (VCDM) must call -initWithFrameReceiver: to +// initialise an object of this class and register a |frameReceiver_|. +// * Frame receiver registration or removal can also happen via explicit call +// to -setFrameReceiver:. Re-registrations are safe and allowed, even during +// capture using this method. +// * Method -setCaptureDevice: must be called at least once with a device +// identifier from +deviceNames. Creates all the necessary AVFoundation +// objects on first call; it connects them ready for capture every time. +// This method should not be called during capture (i.e. between +// -startCapture and -stopCapture). +// * -setCaptureWidth:height:frameRate: is called if a resolution or frame rate +// different than the by default one set by -setCaptureDevice: is needed. +// This method should not be called during capture. This method must be +// called after -setCaptureDevice:. +// * -startCapture registers the notification listeners and starts the +// capture. The capture can be stop using -stopCapture. The capture can be +// restarted and restoped multiple times, reconfiguring or not the device in +// between. +// * -setCaptureDevice can be called with a |nil| value, case in which it stops +// the capture and disconnects the library objects. This step is not +// necessary. +// * Deallocation of the library objects happens gracefully on destruction of +// the VideoCaptureDeviceAVFoundation object. +// +// @interface VideoCaptureDeviceAVFoundationLegacy : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate, VideoCaptureDeviceAVFoundationProtocol> { @@ -24,9 +60,6 @@ int _frameHeight; float _frameRate; - // The capture format that best matches the above attributes. - base::scoped_nsobject<AVCaptureDeviceFormat> _bestCaptureFormat; - base::Lock _lock; // Protects concurrent setting and using |frameReceiver_|. media::VideoCaptureDeviceAVFoundationFrameReceiver* _frameReceiver; // weak. @@ -40,18 +73,55 @@ // An AVDataOutput specialized for taking pictures out of |captureSession_|. base::scoped_nsobject<AVCaptureStillImageOutput> _stillImageOutput; - size_t _takePhotoStartedCount; - size_t _takePhotoPendingCount; - size_t _takePhotoCompletedCount; - bool _stillImageOutputWarmupCompleted; - std::unique_ptr<base::WeakPtrFactory<VideoCaptureDeviceAVFoundationLegacy>> - _weakPtrFactoryForTakePhoto; - // For testing. - base::RepeatingCallback<void()> _onStillImageOutputStopped; - - scoped_refptr<base::SingleThreadTaskRunner> _mainThreadTaskRunner; + base::ThreadChecker _main_thread_checker; } + +// Returns a dictionary of capture devices with friendly name and unique id. ++ (NSDictionary*)deviceNames; + +// Retrieve the capture supported formats for a given device |descriptor|. ++ (void)getDevice:(const media::VideoCaptureDeviceDescriptor&)descriptor + supportedFormats:(media::VideoCaptureFormats*)formats; + +// Initializes the instance and the underlying capture session and registers the +// frame receiver. +- (id)initWithFrameReceiver: + (media::VideoCaptureDeviceAVFoundationFrameReceiver*)frameReceiver; + +// Sets the frame receiver. +- (void)setFrameReceiver: + (media::VideoCaptureDeviceAVFoundationFrameReceiver*)frameReceiver; + +// Sets which capture device to use by name, retrieved via |deviceNames|. Once +// the deviceId is known, the library objects are created if needed and +// connected for the capture, and a by default resolution is set. If deviceId is +// nil, then the eventual capture is stopped and library objects are +// disconnected. Returns YES on success, NO otherwise. If the return value is +// NO, an error message is assigned to |outMessage|. This method should not be +// called during capture. +- (BOOL)setCaptureDevice:(NSString*)deviceId + errorMessage:(NSString**)outMessage; + +// Configures the capture properties for the capture session and the video data +// output; this means it MUST be called after setCaptureDevice:. Return YES on +// success, else NO. +- (BOOL)setCaptureHeight:(int)height + width:(int)width + frameRate:(float)frameRate; + +// Starts video capturing and register the notification listeners. Must be +// called after setCaptureDevice:, and, eventually, also after +// setCaptureHeight:width:frameRate:. Returns YES on success, NO otherwise. +- (BOOL)startCapture; + +// Stops video capturing and stops listening to notifications. +- (void)stopCapture; + +// Takes a photo. This method should only be called between -startCapture and +// -stopCapture. +- (void)takePhoto; + @end -#endif // MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_DEVICE_AVFOUNDATION_LEGACY_MAC_H_ +#endif // MEDIA_CAPTURE_VIDEO_MAC_VIDEO_CAPTURE_DEVICE_AVFOUNDATION_MAC_H_
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.mm index 69865af..ff5523e2 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.mm +++ b/media/capture/video/mac/video_capture_device_avfoundation_legacy_mac.mm
@@ -18,8 +18,6 @@ #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" #include "media/base/timestamp_constants.h" -#include "media/base/video_types.h" -#import "media/capture/video/mac/video_capture_device_avfoundation_utils_mac.h" #include "media/capture/video/mac/video_capture_device_factory_mac.h" #include "media/capture/video/mac/video_capture_device_mac.h" #include "media/capture/video_capture_types.h" @@ -28,21 +26,230 @@ namespace { -constexpr int kTimeToWaitBeforeStoppingStillImageCaptureInSeconds = 60; +enum MacBookVersions { + OTHER = 0, + MACBOOK_5, // MacBook5.X + MACBOOK_6, + MACBOOK_7, + MACBOOK_8, + MACBOOK_PRO_11, // MacBookPro11.X + MACBOOK_PRO_12, + MACBOOK_PRO_13, + MACBOOK_AIR_5, // MacBookAir5.X + MACBOOK_AIR_6, + MACBOOK_AIR_7, + MACBOOK_AIR_8, + MACBOOK_AIR_3, + MACBOOK_AIR_4, + MACBOOK_4, + MACBOOK_9, + MACBOOK_10, + MACBOOK_PRO_10, + MACBOOK_PRO_9, + MACBOOK_PRO_8, + MACBOOK_PRO_7, + MACBOOK_PRO_6, + MACBOOK_PRO_5, + MAX_MACBOOK_VERSION = MACBOOK_PRO_5 +}; + +MacBookVersions GetMacBookModel(const std::string& model) { + struct { + const char* name; + MacBookVersions version; + } static const kModelToVersion[] = { + {"MacBook4,", MACBOOK_4}, {"MacBook5,", MACBOOK_5}, + {"MacBook6,", MACBOOK_6}, {"MacBook7,", MACBOOK_7}, + {"MacBook8,", MACBOOK_8}, {"MacBook9,", MACBOOK_9}, + {"MacBook10,", MACBOOK_10}, {"MacBookPro5,", MACBOOK_PRO_5}, + {"MacBookPro6,", MACBOOK_PRO_6}, {"MacBookPro7,", MACBOOK_PRO_7}, + {"MacBookPro8,", MACBOOK_PRO_8}, {"MacBookPro9,", MACBOOK_PRO_9}, + {"MacBookPro10,", MACBOOK_PRO_10}, {"MacBookPro11,", MACBOOK_PRO_11}, + {"MacBookPro12,", MACBOOK_PRO_12}, {"MacBookPro13,", MACBOOK_PRO_13}, + {"MacBookAir3,", MACBOOK_AIR_3}, {"MacBookAir4,", MACBOOK_AIR_4}, + {"MacBookAir5,", MACBOOK_AIR_5}, {"MacBookAir6,", MACBOOK_AIR_6}, + {"MacBookAir7,", MACBOOK_AIR_7}, {"MacBookAir8,", MACBOOK_AIR_8}, + }; + + for (const auto& entry : kModelToVersion) { + if (base::StartsWith(model, entry.name, + base::CompareCase::INSENSITIVE_ASCII)) { + return entry.version; + } + } + return OTHER; +} + +// Add Uma stats for number of detected devices on MacBooks. These are used for +// investigating crbug/582931. +void MaybeWriteUma(int number_of_devices, int number_of_suspended_devices) { + std::string model = base::mac::GetModelIdentifier(); + if (!base::StartsWith(model, "MacBook", + base::CompareCase::INSENSITIVE_ASCII)) { + return; + } + static int attempt_since_process_start_counter = 0; + static int device_count_at_last_attempt = 0; + static bool has_seen_zero_device_count = false; + const int attempt_count_since_process_start = + ++attempt_since_process_start_counter; + const int retry_count = + media::VideoCaptureDeviceFactoryMac::GetGetDevicesInfoRetryCount(); + const int device_count = number_of_devices + number_of_suspended_devices; + UMA_HISTOGRAM_COUNTS_1M("Media.VideoCapture.MacBook.NumberOfDevices", + device_count); + if (device_count == 0) { + UMA_HISTOGRAM_ENUMERATION( + "Media.VideoCapture.MacBook.HardwareVersionWhenNoCamera", + GetMacBookModel(model), MAX_MACBOOK_VERSION + 1); + if (!has_seen_zero_device_count) { + UMA_HISTOGRAM_COUNTS_1M( + "Media.VideoCapture.MacBook.AttemptCountWhenNoCamera", + attempt_count_since_process_start); + has_seen_zero_device_count = true; + } + } + + if (attempt_count_since_process_start == 1) { + if (retry_count == 0) { + video_capture::uma::LogMacbookRetryGetDeviceInfosEvent( + device_count == 0 + ? video_capture::uma:: + AVF_RECEIVED_ZERO_INFOS_FIRST_TRY_FIRST_ATTEMPT + : video_capture::uma:: + AVF_RECEIVED_NONZERO_INFOS_FIRST_TRY_FIRST_ATTEMPT); + } else { + video_capture::uma::LogMacbookRetryGetDeviceInfosEvent( + device_count == 0 + ? video_capture::uma::AVF_RECEIVED_ZERO_INFOS_RETRY + : video_capture::uma::AVF_RECEIVED_NONZERO_INFOS_RETRY); + } + // attempt count > 1 + } else if (retry_count == 0) { + video_capture::uma::LogMacbookRetryGetDeviceInfosEvent( + device_count == 0 + ? video_capture::uma:: + AVF_RECEIVED_ZERO_INFOS_FIRST_TRY_NONFIRST_ATTEMPT + : video_capture::uma:: + AVF_RECEIVED_NONZERO_INFOS_FIRST_TRY_NONFIRST_ATTEMPT); + } + if (attempt_count_since_process_start > 1 && + device_count != device_count_at_last_attempt) { + video_capture::uma::LogMacbookRetryGetDeviceInfosEvent( + device_count == 0 + ? video_capture::uma::AVF_DEVICE_COUNT_CHANGED_FROM_POSITIVE_TO_ZERO + : video_capture::uma:: + AVF_DEVICE_COUNT_CHANGED_FROM_ZERO_TO_POSITIVE); + } + device_count_at_last_attempt = device_count; +} + +// This function translates Mac Core Video pixel formats to Chromium pixel +// formats. +media::VideoPixelFormat FourCCToChromiumPixelFormat(FourCharCode code) { + switch (code) { + case kCVPixelFormatType_422YpCbCr8: + return media::PIXEL_FORMAT_UYVY; + case kCMPixelFormat_422YpCbCr8_yuvs: + return media::PIXEL_FORMAT_YUY2; + case kCMVideoCodecType_JPEG_OpenDML: + return media::PIXEL_FORMAT_MJPEG; + default: + return media::PIXEL_FORMAT_UNKNOWN; + } +} + +// Extracts |base_address| and |length| out of a SampleBuffer. +void ExtractBaseAddressAndLength(char** base_address, + size_t* length, + CMSampleBufferRef sample_buffer) { + CMBlockBufferRef block_buffer = CMSampleBufferGetDataBuffer(sample_buffer); + DCHECK(block_buffer); + + size_t length_at_offset; + const OSStatus status = CMBlockBufferGetDataPointer( + block_buffer, 0, &length_at_offset, length, base_address); + DCHECK_EQ(noErr, status); + // Expect the (M)JPEG data to be available as a contiguous reference, i.e. + // not covered by multiple memory blocks. + DCHECK_EQ(length_at_offset, *length); +} } // anonymous namespace @implementation VideoCaptureDeviceAVFoundationLegacy +#pragma mark Class methods + ++ (void)getDeviceNames:(NSMutableDictionary*)deviceNames { + // At this stage we already know that AVFoundation is supported and the whole + // library is loaded and initialised, by the device monitoring. + NSArray* devices = [AVCaptureDevice devices]; + int number_of_suspended_devices = 0; + for (AVCaptureDevice* device in devices) { + if ([device hasMediaType:AVMediaTypeVideo] || + [device hasMediaType:AVMediaTypeMuxed]) { + if ([device isSuspended]) { + ++number_of_suspended_devices; + continue; + } + DeviceNameAndTransportType* nameAndTransportType = + [[[DeviceNameAndTransportType alloc] + initWithName:[device localizedName] + transportType:[device transportType]] autorelease]; + [deviceNames setObject:nameAndTransportType forKey:[device uniqueID]]; + } + } + MaybeWriteUma([deviceNames count], number_of_suspended_devices); +} + ++ (NSDictionary*)deviceNames { + NSMutableDictionary* deviceNames = + [[[NSMutableDictionary alloc] init] autorelease]; + // The device name retrieval is not going to happen in the main thread, and + // this might cause instabilities (it did in QTKit), so keep an eye here. + [self getDeviceNames:deviceNames]; + return deviceNames; +} + ++ (void)getDevice:(const media::VideoCaptureDeviceDescriptor&)descriptor + supportedFormats:(media::VideoCaptureFormats*)formats { + NSArray* devices = [AVCaptureDevice devices]; + AVCaptureDevice* device = nil; + for (device in devices) { + if (base::SysNSStringToUTF8([device uniqueID]) == descriptor.device_id) + break; + } + if (device == nil) + return; + for (AVCaptureDeviceFormat* format in device.formats) { + // MediaSubType is a CMPixelFormatType but can be used as CVPixelFormatType + // as well according to CMFormatDescription.h + const media::VideoPixelFormat pixelFormat = FourCCToChromiumPixelFormat( + CMFormatDescriptionGetMediaSubType([format formatDescription])); + + CMVideoDimensions dimensions = + CMVideoFormatDescriptionGetDimensions([format formatDescription]); + + for (AVFrameRateRange* frameRate in + [format videoSupportedFrameRateRanges]) { + media::VideoCaptureFormat format( + gfx::Size(dimensions.width, dimensions.height), + frameRate.maxFrameRate, pixelFormat); + formats->push_back(format); + DVLOG(2) << descriptor.display_name() << " " + << media::VideoCaptureFormat::ToString(format); + } + } +} + #pragma mark Public methods - (id)initWithFrameReceiver: (media::VideoCaptureDeviceAVFoundationFrameReceiver*)frameReceiver { if ((self = [super init])) { - _mainThreadTaskRunner = base::ThreadTaskRunnerHandle::Get(); + DCHECK(_main_thread_checker.CalledOnValidThread()); DCHECK(frameReceiver); - _weakPtrFactoryForTakePhoto = std::make_unique< - base::WeakPtrFactory<VideoCaptureDeviceAVFoundationLegacy>>(self); [self setFrameReceiver:frameReceiver]; _captureSession.reset([[AVCaptureSession alloc] init]); } @@ -50,10 +257,7 @@ } - (void)dealloc { - [self stopStillImageOutput]; [self stopCapture]; - _weakPtrFactoryForTakePhoto = nullptr; - _mainThreadTaskRunner = nullptr; [super dealloc]; } @@ -66,14 +270,15 @@ - (BOOL)setCaptureDevice:(NSString*)deviceId errorMessage:(NSString**)outMessage { DCHECK(_captureSession); - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); + DCHECK(_main_thread_checker.CalledOnValidThread()); if (!deviceId) { // First stop the capture session, if it's running. [self stopCapture]; // Now remove the input and output from the capture session. [_captureSession removeOutput:_captureVideoDataOutput]; - [self stopStillImageOutput]; + if (_stillImageOutput) + [_captureSession removeOutput:_stillImageOutput]; if (_captureDeviceInput) { DCHECK(_captureDevice); [_captureSession stopRunning]; @@ -108,6 +313,12 @@ } [_captureSession addInput:_captureDeviceInput]; + // Create and plug the still image capture output. This should happen in + // advance of the actual picture to allow for the 3A to stabilize. + _stillImageOutput.reset([[AVCaptureStillImageOutput alloc] init]); + if (_stillImageOutput && [_captureSession canAddOutput:_stillImageOutput]) + [_captureSession addOutput:_stillImageOutput]; + // Create a new data output for video. The data output is configured to // discard late frames by default. _captureVideoDataOutput.reset([[AVCaptureVideoDataOutput alloc] init]); @@ -130,30 +341,28 @@ - (BOOL)setCaptureHeight:(int)height width:(int)width frameRate:(float)frameRate { - DCHECK(![_captureSession isRunning]); - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); + DCHECK(![_captureSession isRunning] && + _main_thread_checker.CalledOnValidThread()); _frameWidth = width; _frameHeight = height; _frameRate = frameRate; - _bestCaptureFormat.reset( - media::FindBestCaptureFormat([_captureDevice formats], width, height, - frameRate), - base::scoped_policy::RETAIN); - // Default to NV12, a pixel format commonly supported by web cameras. - FourCharCode best_fourcc = - kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; // NV12 (a.k.a. 420v) - if (_bestCaptureFormat) { - best_fourcc = CMFormatDescriptionGetMediaSubType( - [_bestCaptureFormat formatDescription]); + + FourCharCode best_fourcc = kCMPixelFormat_422YpCbCr8; + for (AVCaptureDeviceFormat* format in [_captureDevice formats]) { + const FourCharCode fourcc = + CMFormatDescriptionGetMediaSubType([format formatDescription]); + // Compare according to Chromium preference. + if (media::VideoCaptureFormat::ComparePixelFormatPreference( + FourCCToChromiumPixelFormat(fourcc), + FourCCToChromiumPixelFormat(best_fourcc))) { + best_fourcc = fourcc; + } } if (best_fourcc == kCMVideoCodecType_JPEG_OpenDML) { - // Capturing MJPEG directly never worked. Request a conversion to what has - // historically been the default pixel format. - // TODO(https://crbug.com/1124884): Investigate the performance of - // performing MJPEG ourselves. - best_fourcc = kCMPixelFormat_422YpCbCr8; + [_captureSession removeOutput:_stillImageOutput]; + _stillImageOutput.reset(); } // The capture output has to be configured, despite Mac documentation @@ -195,7 +404,7 @@ } - (BOOL)startCapture { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); + DCHECK(_main_thread_checker.CalledOnValidThread()); if (!_captureSession) { DLOG(ERROR) << "Video capture session not initialized."; return NO; @@ -207,207 +416,60 @@ name:AVCaptureSessionRuntimeErrorNotification object:_captureSession]; [_captureSession startRunning]; - - // Update the active capture format once the capture session is running. - // Setting it before the capture session is running has no effect. - if (_bestCaptureFormat) { - if ([_captureDevice lockForConfiguration:nil]) { - [_captureDevice setActiveFormat:_bestCaptureFormat]; - [_captureDevice unlockForConfiguration]; - } - } - return YES; } - (void)stopCapture { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); - [self stopStillImageOutput]; + DCHECK(_main_thread_checker.CalledOnValidThread()); if ([_captureSession isRunning]) [_captureSession stopRunning]; // Synchronous. [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)takePhoto { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); + DCHECK(_main_thread_checker.CalledOnValidThread()); DCHECK([_captureSession isRunning]); + if (!_stillImageOutput) + return; - ++_takePhotoStartedCount; - - // Ready to take a photo immediately? - if (_stillImageOutput && _stillImageOutputWarmupCompleted) { - [self takePhotoInternal]; + DCHECK_EQ(1u, [[_stillImageOutput connections] count]); + AVCaptureConnection* const connection = + [[_stillImageOutput connections] firstObject]; + if (!connection) { + base::AutoLock lock(_lock); + _frameReceiver->OnPhotoError(); return; } - // Lazily instantiate the |_stillImageOutput| the first time takePhoto() is - // called. When takePhoto() isn't called, this avoids JPEG compession work for - // every frame. This can save a lot of CPU in some cases (see - // https://crbug.com/1116241). However because it can take a couple of second - // for the 3A to stabilize, lazily instantiating like may result in noticeable - // delays. To avoid delays in future takePhoto() calls we don't delete - // |_stillImageOutput| until takePhoto() has not been called for 60 seconds. - if (!_stillImageOutput) { - // We use AVCaptureStillImageOutput for historical reasons, but note that it - // has been deprecated in macOS 10.15[1] in favor of - // AVCapturePhotoOutput[2]. - // - // [1] - // https://developer.apple.com/documentation/avfoundation/avcapturestillimageoutput - // [2] - // https://developer.apple.com/documentation/avfoundation/avcapturephotooutput - // TODO(https://crbug.com/1124322): Migrate to the new API. - _stillImageOutput.reset([[AVCaptureStillImageOutput alloc] init]); - if (!_stillImageOutput || - ![_captureSession canAddOutput:_stillImageOutput]) { - // Complete this started photo as error. - ++_takePhotoPendingCount; - { - base::AutoLock lock(_lock); - if (_frameReceiver) { - _frameReceiver->OnPhotoError(); - } - } - [self takePhotoCompleted]; + const auto handler = ^(CMSampleBufferRef sampleBuffer, NSError* error) { + base::AutoLock lock(_lock); + if (!_frameReceiver) + return; + if (error != nil) { + _frameReceiver->OnPhotoError(); return; } - [_captureSession addOutput:_stillImageOutput]; - // A delay is needed before taking the photo or else the photo may be dark. - // 2 seconds was enough in manual testing; we delay by 3 for good measure. - _mainThreadTaskRunner->PostDelayedTask( - FROM_HERE, - base::BindOnce( - [](base::WeakPtr<VideoCaptureDeviceAVFoundationLegacy> weakSelf) { - [weakSelf.get() takePhotoInternal]; - }, - _weakPtrFactoryForTakePhoto->GetWeakPtr()), - base::TimeDelta::FromSeconds(3)); - } -} -- (void)setOnStillImageOutputStoppedForTesting: - (base::RepeatingCallback<void()>)onStillImageOutputStopped { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); - _onStillImageOutputStopped = onStillImageOutputStopped; + // Recommended compressed pixel format is JPEG, we don't expect surprises. + // TODO(mcasas): Consider using [1] for merging EXIF output information: + // [1] +(NSData*)jpegStillImageNSDataRepresentation:jpegSampleBuffer; + DCHECK_EQ(kCMVideoCodecType_JPEG, + CMFormatDescriptionGetMediaSubType( + CMSampleBufferGetFormatDescription(sampleBuffer))); + + char* baseAddress = 0; + size_t length = 0; + ExtractBaseAddressAndLength(&baseAddress, &length, sampleBuffer); + _frameReceiver->OnPhotoTaken(reinterpret_cast<uint8_t*>(baseAddress), + length, "image/jpeg"); + }; + + [_stillImageOutput captureStillImageAsynchronouslyFromConnection:connection + completionHandler:handler]; } #pragma mark Private methods -- (void)takePhotoInternal { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); - // stopStillImageOutput invalidates all weak ptrs, meaning in-flight - // operations are affectively cancelled. So if this method is running, still - // image output must be good to go. - DCHECK([_captureSession isRunning]); - DCHECK(_stillImageOutput); - DCHECK([[_stillImageOutput connections] count] == 1); - AVCaptureConnection* const connection = - [[_stillImageOutput connections] firstObject]; - DCHECK(connection); - _stillImageOutputWarmupCompleted = true; - - // For all photos started that are not yet pending, take photos. - while (_takePhotoPendingCount < _takePhotoStartedCount) { - ++_takePhotoPendingCount; - const auto handler = ^(CMSampleBufferRef sampleBuffer, NSError* error) { - { - base::AutoLock lock(_lock); - if (_frameReceiver) { - if (error != nil) { - _frameReceiver->OnPhotoError(); - } else { - // Recommended compressed pixel format is JPEG, we don't expect - // surprises. - // TODO(mcasas): Consider using [1] for merging EXIF output - // information: - // [1] - // +(NSData*)jpegStillImageNSDataRepresentation:jpegSampleBuffer; - DCHECK_EQ(kCMVideoCodecType_JPEG, - CMFormatDescriptionGetMediaSubType( - CMSampleBufferGetFormatDescription(sampleBuffer))); - - char* baseAddress = 0; - size_t length = 0; - media::ExtractBaseAddressAndLength(&baseAddress, &length, - sampleBuffer); - _frameReceiver->OnPhotoTaken( - reinterpret_cast<uint8_t*>(baseAddress), length, "image/jpeg"); - } - } - } - // Called both on success and failure. - _mainThreadTaskRunner->PostTask( - FROM_HERE, - base::BindOnce( - [](base::WeakPtr<VideoCaptureDeviceAVFoundationLegacy> weakSelf) { - [weakSelf.get() takePhotoCompleted]; - }, - _weakPtrFactoryForTakePhoto->GetWeakPtr())); - }; - [_stillImageOutput captureStillImageAsynchronouslyFromConnection:connection - completionHandler:handler]; - } -} - -- (void)takePhotoCompleted { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); - ++_takePhotoCompletedCount; - if (_takePhotoStartedCount != _takePhotoCompletedCount) - return; - // All pending takePhoto()s have completed. If no more photos are taken - // within 60 seconds, stop still image output to avoid expensive MJPEG - // conversions going forward. - _mainThreadTaskRunner->PostDelayedTask( - FROM_HERE, - base::BindOnce( - [](base::WeakPtr<VideoCaptureDeviceAVFoundationLegacy> weakSelf, - size_t takePhotoCount) { - VideoCaptureDeviceAVFoundationLegacy* strongSelf = weakSelf.get(); - if (!strongSelf) - return; - // Don't stop the still image output if takePhoto() was called - // while the task was pending. - if (strongSelf->_takePhotoStartedCount != takePhotoCount) - return; - [strongSelf stopStillImageOutput]; - }, - _weakPtrFactoryForTakePhoto->GetWeakPtr(), _takePhotoStartedCount), - base::TimeDelta::FromSeconds( - kTimeToWaitBeforeStoppingStillImageCaptureInSeconds)); -} - -- (void)stopStillImageOutput { - DCHECK(_mainThreadTaskRunner->BelongsToCurrentThread()); - if (!_stillImageOutput) { - // Already stopped. - return; - } - if (_captureSession) { - [_captureSession removeOutput:_stillImageOutput]; - } - _stillImageOutput.reset(); - _stillImageOutputWarmupCompleted = false; - - // Cancel all in-flight operations. - _weakPtrFactoryForTakePhoto->InvalidateWeakPtrs(); - // Report error for all pending calls that were stopped. - size_t pendingCalls = _takePhotoStartedCount - _takePhotoCompletedCount; - _takePhotoCompletedCount = _takePhotoPendingCount = _takePhotoStartedCount; - { - base::AutoLock lock(_lock); - if (_frameReceiver) { - for (size_t i = 0; i < pendingCalls; ++i) { - _frameReceiver->OnPhotoError(); - } - } - } - - if (_onStillImageOutputStopped) { - // Callback used by tests. - _onStillImageOutputStopped.Run(); - } -} - // |captureOutput| is called by the capture device to deliver a new frame. // AVFoundation calls from a number of threads, depending on, at least, if // Chrome is on foreground or background. @@ -422,7 +484,7 @@ CMVideoFormatDescriptionGetDimensions(formatDescription); const media::VideoCaptureFormat captureFormat( gfx::Size(dimensions.width, dimensions.height), _frameRate, - media::FourCCToChromiumPixelFormat(fourcc)); + FourCCToChromiumPixelFormat(fourcc)); gfx::ColorSpace colorSpace; // We have certain format expectation for capture output: @@ -441,25 +503,9 @@ if (videoFrame && CVPixelBufferLockBaseAddress(videoFrame, kCVPixelBufferLock_ReadOnly) == kCVReturnSuccess) { - if (!CVPixelBufferIsPlanar(videoFrame)) { - // For nonplanar buffers, CVPixelBufferGetBaseAddress returns a pointer - // to (0,0). (For planar buffers, it returns something else.) - // https://developer.apple.com/documentation/corevideo/1457115-cvpixelbuffergetbaseaddress?language=objc - baseAddress = - static_cast<char*>(CVPixelBufferGetBaseAddress(videoFrame)); - } else { - // For planar buffers, CVPixelBufferGetBaseAddressOfPlane() is used. If - // the buffer is contiguous (CHECK'd below) then we only need to know - // the address of the first plane, regardless of - // CVPixelBufferGetPlaneCount(). - baseAddress = static_cast<char*>( - CVPixelBufferGetBaseAddressOfPlane(videoFrame, 0)); - } - // CVPixelBufferGetDataSize() works for both nonplanar and planar buffers - // as long as they are contiguous in memory. - frameSize = CVPixelBufferGetDataSize(videoFrame); - // Only contiguous buffers are supported. - CHECK(frameSize); + baseAddress = static_cast<char*>(CVPixelBufferGetBaseAddress(videoFrame)); + frameSize = CVPixelBufferGetHeight(videoFrame) * + CVPixelBufferGetBytesPerRow(videoFrame); // TODO(julien.isorce): move GetImageBufferColorSpace(CVImageBufferRef) // from media::VTVideoDecodeAccelerator to media/base/mac and call it @@ -470,7 +516,7 @@ } } if (!videoFrame) { - media::ExtractBaseAddressAndLength(&baseAddress, &frameSize, sampleBuffer); + ExtractBaseAddressAndLength(&baseAddress, &frameSize, sampleBuffer); } {
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm index 3286dced..7073f0c 100644 --- a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm +++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
@@ -142,9 +142,8 @@ media::FindBestCaptureFormat([_captureDevice formats], width, height, frameRate), base::scoped_policy::RETAIN); - // Default to NV12, a pixel format commonly supported by web cameras. - FourCharCode best_fourcc = - kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange; // NV12 (a.k.a. 420v) + + FourCharCode best_fourcc = kCMPixelFormat_422YpCbCr8; if (_bestCaptureFormat) { best_fourcc = CMFormatDescriptionGetMediaSubType( [_bestCaptureFormat formatDescription]); @@ -443,25 +442,9 @@ if (videoFrame && CVPixelBufferLockBaseAddress(videoFrame, kCVPixelBufferLock_ReadOnly) == kCVReturnSuccess) { - if (!CVPixelBufferIsPlanar(videoFrame)) { - // For nonplanar buffers, CVPixelBufferGetBaseAddress returns a pointer - // to (0,0). (For planar buffers, it returns something else.) - // https://developer.apple.com/documentation/corevideo/1457115-cvpixelbuffergetbaseaddress?language=objc - baseAddress = - static_cast<char*>(CVPixelBufferGetBaseAddress(videoFrame)); - } else { - // For planar buffers, CVPixelBufferGetBaseAddressOfPlane() is used. If - // the buffer is contiguous (CHECK'd below) then we only need to know - // the address of the first plane, regardless of - // CVPixelBufferGetPlaneCount(). - baseAddress = static_cast<char*>( - CVPixelBufferGetBaseAddressOfPlane(videoFrame, 0)); - } - // CVPixelBufferGetDataSize() works for both nonplanar and planar buffers - // as long as they are contiguous in memory. - frameSize = CVPixelBufferGetDataSize(videoFrame); - // Only contiguous buffers are supported. - CHECK(frameSize); + baseAddress = static_cast<char*>(CVPixelBufferGetBaseAddress(videoFrame)); + frameSize = CVPixelBufferGetHeight(videoFrame) * + CVPixelBufferGetBytesPerRow(videoFrame); // TODO(julien.isorce): move GetImageBufferColorSpace(CVImageBufferRef) // from media::VTVideoDecodeAccelerator to media/base/mac and call it
diff --git a/media/gpu/chromeos/video_decoder_pipeline.cc b/media/gpu/chromeos/video_decoder_pipeline.cc index 3759f9f9..dd1544f 100644 --- a/media/gpu/chromeos/video_decoder_pipeline.cc +++ b/media/gpu/chromeos/video_decoder_pipeline.cc
@@ -496,7 +496,8 @@ return main_frame_pool_.get(); } -base::Optional<Fourcc> VideoDecoderPipeline::PickDecoderOutputFormat( +base::Optional<std::pair<Fourcc, gfx::Size>> +VideoDecoderPipeline::PickDecoderOutputFormat( const std::vector<std::pair<Fourcc, gfx::Size>>& candidates, const gfx::Rect& visible_rect) { DVLOGF(3); @@ -513,8 +514,13 @@ for (const auto& candidate : candidates) fourccs.push_back(candidate.first); const auto renderable_fourcc = PickRenderableFourcc(fourccs); - if (renderable_fourcc) - return renderable_fourcc; + if (renderable_fourcc) { + for (const auto& candidate : candidates) + if (candidate.first == renderable_fourcc) + return candidate; + DVLOGF(2) << "Renderable Fourcc not in candidates list. This is a bug."; + return base::nullopt; + } std::unique_ptr<ImageProcessor> image_processor = ImageProcessorFactory::CreateWithInputCandidates( @@ -529,6 +535,7 @@ // Note that fourcc is specified in ImageProcessor's factory method. auto fourcc = image_processor->input_config().fourcc; + auto size = image_processor->input_config().size; // Setup new pipeline. image_processor_ = ImageProcessorWithPool::Create( @@ -539,7 +546,7 @@ return base::nullopt; } - return fourcc; + return std::make_pair(fourcc, size); } void VideoDecoderPipeline::OnImageProcessorError() {
diff --git a/media/gpu/chromeos/video_decoder_pipeline.h b/media/gpu/chromeos/video_decoder_pipeline.h index c0c6ac10..16287e243 100644 --- a/media/gpu/chromeos/video_decoder_pipeline.h +++ b/media/gpu/chromeos/video_decoder_pipeline.h
@@ -59,10 +59,12 @@ // flushed. virtual void PrepareChangeResolution() = 0; - // Return a valid format for |decoder_| output from given |candidates| and - // the visible rect. + // Return a valid format and size for |decoder_| output from given + // |candidates| and the visible rect. The size might be modified from the + // ones provided originally to accommodate the needs of the pipeline. // Return base::nullopt if no valid format is found. - virtual base::Optional<Fourcc> PickDecoderOutputFormat( + virtual base::Optional<std::pair<Fourcc, gfx::Size>> + PickDecoderOutputFormat( const std::vector<std::pair<Fourcc, gfx::Size>>& candidates, const gfx::Rect& visible_rect) = 0; }; @@ -164,7 +166,7 @@ // After picking a format, it instantiates an |image_processor_| if none of // format in |candidates| is renderable and an ImageProcessor can convert a // candidate to renderable format. - base::Optional<Fourcc> PickDecoderOutputFormat( + base::Optional<std::pair<Fourcc, gfx::Size>> PickDecoderOutputFormat( const std::vector<std::pair<Fourcc, gfx::Size>>& candidates, const gfx::Rect& visible_rect) override;
diff --git a/media/gpu/v4l2/v4l2_video_decoder.cc b/media/gpu/v4l2/v4l2_video_decoder.cc index 67e3502..53937b7 100644 --- a/media/gpu/v4l2/v4l2_video_decoder.cc +++ b/media/gpu/v4l2/v4l2_video_decoder.cc
@@ -302,24 +302,26 @@ } // Ask the pipeline to pick the output format. - const base::Optional<Fourcc> fourcc = + const base::Optional<std::pair<Fourcc, gfx::Size>> output_format = client_->PickDecoderOutputFormat(candidates, visible_rect); - if (!fourcc) { - VLOGF(1) << "Failed to pick a output format."; + if (!output_format) { + VLOGF(1) << "Failed to pick an output format."; return false; } + Fourcc fourcc = std::move(output_format->first); + gfx::Size picked_size = std::move(output_format->second); // We successfully picked the output format. Now setup output format again. base::Optional<struct v4l2_format> format = - output_queue_->SetFormat(fourcc->ToV4L2PixFmt(), size, 0); + output_queue_->SetFormat(fourcc.ToV4L2PixFmt(), picked_size, 0); DCHECK(format); gfx::Size adjusted_size(format->fmt.pix_mp.width, format->fmt.pix_mp.height); DCHECK_EQ(adjusted_size.width() % 16, 0); DCHECK_EQ(adjusted_size.height() % 16, 0); - if (!gfx::Rect(adjusted_size).Contains(gfx::Rect(size))) { + if (!gfx::Rect(adjusted_size).Contains(gfx::Rect(picked_size))) { VLOGF(1) << "The adjusted coded size (" << adjusted_size.ToString() - << ") should contains the original coded size(" << size.ToString() - << ")."; + << ") should contains the original coded size(" + << picked_size.ToString() << ")."; return false; } @@ -331,7 +333,7 @@ DmabufVideoFramePool* pool = client_->GetVideoFramePool(); if (pool) { base::Optional<GpuBufferLayout> layout = pool->Initialize( - *fourcc, adjusted_size, visible_rect, + fourcc, adjusted_size, visible_rect, GetNaturalSize(visible_rect, pixel_aspect_ratio_), num_output_frames_); if (!layout) { VLOGF(1) << "Failed to setup format to VFPool"; @@ -339,7 +341,7 @@ } if (layout->size() != adjusted_size) { VLOGF(1) << "The size adjusted by VFPool is different from one " - << "adjusted by a video driver. fourcc: " << fourcc->ToString() + << "adjusted by a video driver. fourcc: " << fourcc.ToString() << ", (video driver v.s. VFPool) " << adjusted_size.ToString() << " != " << layout->size().ToString(); return false; @@ -348,7 +350,7 @@ if (layout->modifier() && layout->modifier() != gfx::NativePixmapHandle::kNoModifier) { base::Optional<struct v4l2_format> modifier_format = - output_queue_->SetModifierFormat(layout->modifier(), size); + output_queue_->SetModifierFormat(layout->modifier(), picked_size); if (!modifier_format) return false;
diff --git a/services/network/public/cpp/features.cc b/services/network/public/cpp/features.cc index f5cab38..97eee7f 100644 --- a/services/network/public/cpp/features.cc +++ b/services/network/public/cpp/features.cc
@@ -239,7 +239,7 @@ // Enables the Content Security Policy Embedded Enforcement check out of blink const base::Feature kOutOfBlinkCSPEE{"OutOfBlinkCSPEE", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kWebSocketReassembleShortMessages{ "WebSocketReassembleShortMessages", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index c85e96d..c93e7523 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -1718,36 +1718,6 @@ ] } ], - "ContentIndexingDownloadHome": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "ContentIndexingDownloadHome", - "enable_features": [ - "ContentIndexingDownloadHome" - ] - } - ] - } - ], - "ContentIndexingNTP": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "ContentIndexingNTP", - "enable_features": [ - "ContentIndexingNTP" - ] - } - ] - } - ], "ContextualSearch": [ { "platforms": [
diff --git a/third_party/blink/perf_tests/parser/resources/html5.html b/third_party/blink/perf_tests/parser/resources/html5.html index 0a0ba53..9485483 100644 --- a/third_party/blink/perf_tests/parser/resources/html5.html +++ b/third_party/blink/perf_tests/parser/resources/html5.html
@@ -9528,7 +9528,7 @@ simply being the primary interface of the document object, it is no longer defined as inheriting from <code><a href=#document>Document</a></code>.</p> - <pre class=idl>[LegacyOverrideBuiltins] + <pre class=idl>[LegacyOverrideBuiltIns] interface <dfn id=htmldocument>HTMLDocument</dfn> { // <a href=#resource-metadata-management>resource metadata management</a> [PutForwards=<a href=#dom-location-href title=dom-location-href>href</a>] readonly attribute <a href=#location>Location</a>? <a href=#dom-document-location title=dom-document-location>location</a>; @@ -10222,7 +10222,7 @@ <!-- Note that this named getter overrides built-in properties, as in: http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0D%0A...%3Ciframe%20name%3Dbody%3E%3C%2Fiframe%3E%3Cscript%3Ew(document.body)%3C%2Fscript%3E - This is what the "LegacyOverrideBuiltins" bit means in the IDL. + This is what the "LegacyOverrideBuiltIns" bit means in the IDL. --> </ol><p><dfn id=dom-document-nameditem-filter title=dom-document-nameditem-filter>Named elements</dfn> @@ -42582,7 +42582,7 @@ <dd><code title=attr-fs-target><a href=#attr-fs-target>target</a></code></dd> <dt>DOM interface:</dt> <dd> -<pre class=idl>[LegacyOverrideBuiltins] +<pre class=idl>[LegacyOverrideBuiltIns] interface <dfn id=htmlformelement>HTMLFormElement</dfn> : <a href=#htmlelement>HTMLElement</a> { attribute DOMString <a href=#dom-form-acceptcharset title=dom-form-acceptCharset>acceptCharset</a>; attribute DOMString <a href=#dom-fs-action title=dom-fs-action>action</a>;
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md index d4fa355e..576f042 100644 --- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.md +++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.md
@@ -92,7 +92,7 @@ [ImplementedAs=setItem] setter DOMString (unsigned long index); ``` -There is one interface extended attribute that only affects special operations: `[LegacyOverrideBuiltins]`. +There is one interface extended attribute that only affects special operations: `[LegacyOverrideBuiltIns]`. The following extended attributes are used on special operations, as on methods generally: `[RaisesException]`. @@ -408,9 +408,9 @@ }; ``` -### [LegacyOverrideBuiltins] _(i)_ +### [LegacyOverrideBuiltIns] _(i)_ -Standard: [LegacyOverrideBuiltins](https://heycam.github.io/webidl/#OverrideBuiltins) +Standard: [LegacyOverrideBuiltIns](https://heycam.github.io/webidl/#LegacyOverrideBuiltIns) Summary: Affects named property operations, making named properties shadow built-in properties of the object.
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt index c4c8b427..c5717fa 100644 --- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt +++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -68,7 +68,7 @@ LegacyLenientSetter LegacyLenientThis LegacyNoInterfaceObject -LegacyOverrideBuiltins +LegacyOverrideBuiltIns LegacyTreatAsPartialInterface LegacyTreatNonObjectAsNull LegacyUnenumerableNamedProperties
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc index 81287dbc..4f4efaa 100644 --- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc +++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -473,7 +473,7 @@ // GetNamedProperty(), Getter(), NamedItemAdded(), and NamedItemRemoved() // optimize property access performance for Document. // -// Document interface has [LegacyOverrideBuiltins] and a named getter. If we +// Document interface has [LegacyOverrideBuiltIns] and a named getter. If we // implemented the named getter as a standard IDL-mapped code, we would call a // Blink function before any of Document property access, and it would be // performance overhead even for builtin properties. Our implementation updates
diff --git a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py index f0f9d07..150916b 100644 --- a/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py +++ b/third_party/blink/renderer/bindings/scripts/bind_gen/interface.py
@@ -2751,6 +2751,17 @@ body = func_def.body if not cg_context.named_property_setter: + if ("OverrideBuiltins" in cg_context.interface.extended_attributes + or "LegacyOverrideBuiltins" in + cg_context.interface.extended_attributes): + body.append( + TextNode("""\ +// [LegacyOverrideBuiltIns] +if (${info}.Holder()->GetRealNamedPropertyAttributesInPrototypeChain( + ${current_context}, ${v8_property_name}).IsJust()) { + return; // Fallback to the existing property. +} +""")) body.append( TextNode("""\ // 3.8.2. [[Set]] @@ -3028,7 +3039,7 @@ // https://heycam.github.io/webidl/#LegacyPlatformObjectGetOwnProperty\ """)) - if ("LegacyOverrideBuiltins" not in + if ("LegacyOverrideBuiltIns" not in cg_context.interface.extended_attributes): body.append( TextNode("""\ @@ -5745,7 +5756,7 @@ and props.named_setter.owner, props.named_deleter and props.named_deleter.owner)) flags = ["v8::PropertyHandlerFlags::kOnlyInterceptStrings"] - if "LegacyOverrideBuiltins" not in interface.extended_attributes: + if "LegacyOverrideBuiltIns" not in interface.extended_attributes: flags.append("v8::PropertyHandlerFlags::kNonMasking") if (props.named_getter.extended_attributes.value_of("Affects") == "Nothing"):
diff --git a/third_party/blink/renderer/bindings/scripts/v8_interface.py b/third_party/blink/renderer/bindings/scripts/v8_interface.py index 9c51fcd..a4326041 100644 --- a/third_party/blink/renderer/bindings/scripts/v8_interface.py +++ b/third_party/blink/renderer/bindings/scripts/v8_interface.py
@@ -593,7 +593,7 @@ 'indexed_property_deleter': property_deleter(interface.indexed_property_deleter), 'is_override_builtins': - 'LegacyOverrideBuiltins' in extended_attributes, + 'LegacyOverrideBuiltIns' in extended_attributes, 'named_property_getter': property_getter(interface.named_property_getter, ['name']), 'named_property_setter':
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_special_operations.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_special_operations.idl index aecea67..cfae4bb 100644 --- a/third_party/blink/renderer/bindings/tests/idls/core/test_special_operations.idl +++ b/third_party/blink/renderer/bindings/tests/idls/core/test_special_operations.idl
@@ -3,10 +3,10 @@ // found in the LICENSE file. [ - LegacyOverrideBuiltins + LegacyOverrideBuiltIns ] interface TestSpecialOperations { // [ImplementedAs], union return, nullability - // [LegacyOverrideBuiltins] affects named property operations + // [LegacyOverrideBuiltIns] affects named property operations [ImplementedAs=getItem] getter (Node or NodeList) namedItem(DOMString name); setter Node (DOMString name, Node? value); };
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index 1301aa2..a6ec49ef 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -1523,6 +1523,8 @@ sources = [ "frame/frame_test_helpers.cc", "frame/frame_test_helpers.h", + "html/media/html_media_test_helper.cc", + "html/media/html_media_test_helper.h", "script/mock_script_element_base.h", "testing/core_unit_test_helper.cc", "testing/core_unit_test_helper.h",
diff --git a/third_party/blink/renderer/core/css/css_selector.cc b/third_party/blink/renderer/core/css/css_selector.cc index c80876d5..5a1440b 100644 --- a/third_party/blink/renderer/core/css/css_selector.cc +++ b/third_party/blink/renderer/core/css/css_selector.cc
@@ -871,7 +871,7 @@ for (const CSSSelector* sub_selector = first_sub_selector; sub_selector; sub_selector = CSSSelectorList::Next(*sub_selector)) { if (sub_selector != first_sub_selector) - builder.Append(','); + builder.Append(", "); builder.Append(sub_selector->SelectorText()); } builder.Append(')');
diff --git a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc index 4a7faa49..42f15c1 100644 --- a/third_party/blink/renderer/core/css/resolver/style_adjuster.cc +++ b/third_party/blink/renderer/core/css/resolver/style_adjuster.cc
@@ -695,7 +695,7 @@ style.AdjustMaskLayers(); // Let the theme also have a crack at adjusting the style. - LayoutTheme::GetTheme().AdjustStyle(style, element); + LayoutTheme::GetTheme().AdjustStyle(element, style); AdjustStyleForEditing(style);
diff --git a/third_party/blink/renderer/core/dom/dom_string_map.idl b/third_party/blink/renderer/core/dom/dom_string_map.idl index 755e355..d9842fc2 100644 --- a/third_party/blink/renderer/core/dom/dom_string_map.idl +++ b/third_party/blink/renderer/core/dom/dom_string_map.idl
@@ -26,7 +26,7 @@ // https://html.spec.whatwg.org/C/#the-domstringmap-interface [ - LegacyOverrideBuiltins, + LegacyOverrideBuiltIns, Exposed=Window ] interface DOMStringMap { [ImplementedAs=item] getter DOMString (DOMString name);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 3d8244d..b020369 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -3384,6 +3384,10 @@ return EnsureElementRareData().EnsureElementInternals(To<HTMLElement>(*this)); } +const ElementInternals* Element::GetElementInternals() const { + return HasRareData() ? GetElementRareData()->GetElementInternals() : nullptr; +} + ShadowRoot* Element::createShadowRoot(ExceptionState& exception_state) { DCHECK(RuntimeEnabledFeatures::ShadowDOMV0Enabled(GetExecutionContext())); if (ShadowRoot* root = GetShadowRoot()) {
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h index de1c901..2d88b0c4 100644 --- a/third_party/blink/renderer/core/dom/element.h +++ b/third_party/blink/renderer/core/dom/element.h
@@ -828,6 +828,7 @@ void SetDidAttachInternals(); bool DidAttachInternals() const; ElementInternals& EnsureElementInternals(); + const ElementInternals* GetElementInternals() const; bool ContainsFullScreenElement() const { return HasElementFlag(ElementFlags::kContainsFullScreenElement);
diff --git a/third_party/blink/renderer/core/dom/element_rare_data.h b/third_party/blink/renderer/core/dom/element_rare_data.h index 21c5a80..24cdeb92 100644 --- a/third_party/blink/renderer/core/dom/element_rare_data.h +++ b/third_party/blink/renderer/core/dom/element_rare_data.h
@@ -144,6 +144,9 @@ void SetDidAttachInternals() { did_attach_internals_ = true; } bool DidAttachInternals() const { return did_attach_internals_; } ElementInternals& EnsureElementInternals(HTMLElement& target); + const ElementInternals* GetElementInternals() const { + return element_internals_; + } void SetStyleShouldForceLegacyLayout(bool force) { style_should_force_legacy_layout_ = force;
diff --git a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc index 797e4179..88cc50a 100644 --- a/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc +++ b/third_party/blink/renderer/core/frame/csp/content_security_policy_test.cc
@@ -4,6 +4,8 @@ #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h" +#include "base/test/scoped_feature_list.h" +#include "services/network/public/cpp/features.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/security_context/insecure_request_policy.h" #include "third_party/blink/public/mojom/security_context/insecure_request_policy.mojom-blink.h" @@ -685,7 +687,12 @@ } } +// TODO(antoniosartori): Remove this test and the function +// ContentSecurityPolicy::Subsumes when we remove the feature flag. TEST_F(ContentSecurityPolicyTest, Subsumes) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE); + auto* other = MakeGarbageCollected<ContentSecurityPolicy>(); EXPECT_TRUE(csp->Subsumes(*other)); EXPECT_TRUE(other->Subsumes(*csp)); @@ -905,7 +912,12 @@ SchemeRegistry::RemoveURLSchemeAsNotAllowingJavascriptURLs("https"); } +// TODO(antoniosartori): Remove this test and the function +// ContentSecurityPolicy::IsValidCSPAttr when we remove the feature flag. TEST_F(ContentSecurityPolicyTest, IsValidCSPAttrTest) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE); + // Empty string is invalid EXPECT_FALSE(ContentSecurityPolicy::IsValidCSPAttr("", ""));
diff --git a/third_party/blink/renderer/core/html/BUILD.gn b/third_party/blink/renderer/core/html/BUILD.gn index 52d299b..82ca9704 100644 --- a/third_party/blink/renderer/core/html/BUILD.gn +++ b/third_party/blink/renderer/core/html/BUILD.gn
@@ -687,8 +687,6 @@ "media/autoplay_uma_helper_test.cc", "media/html_media_element_event_listeners_test.cc", "media/html_media_element_test.cc", - "media/html_media_test_helper.cc", - "media/html_media_test_helper.h", "media/html_video_element_persistent_test.cc", "media/html_video_element_test.cc", "media/media_custom_controls_fullscreen_detector_test.cc",
diff --git a/third_party/blink/renderer/core/html/forms/html_form_element.idl b/third_party/blink/renderer/core/html/forms/html_form_element.idl index 8e6f5bb..aa4293e 100644 --- a/third_party/blink/renderer/core/html/forms/html_form_element.idl +++ b/third_party/blink/renderer/core/html/forms/html_form_element.idl
@@ -23,7 +23,7 @@ [ Exposed=Window, HTMLConstructor, - LegacyOverrideBuiltins + LegacyOverrideBuiltIns ] interface HTMLFormElement : HTMLElement { [CEReactions, Reflect=accept_charset] attribute DOMString acceptCharset; [CEReactions, URL] attribute USVString action;
diff --git a/third_party/blink/renderer/core/html/forms/radio_node_list.cc b/third_party/blink/renderer/core/html/forms/radio_node_list.cc index d2bfedd8..b8d28ff 100644 --- a/third_party/blink/renderer/core/html/forms/radio_node_list.cc +++ b/third_party/blink/renderer/core/html/forms/radio_node_list.cc
@@ -27,6 +27,7 @@ #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/dom/node_rare_data.h" +#include "third_party/blink/renderer/core/html/custom/element_internals.h" #include "third_party/blink/renderer/core/html/forms/html_form_element.h" #include "third_party/blink/renderer/core/html/forms/html_input_element.h" #include "third_party/blink/renderer/core/html/html_image_element.h" @@ -92,20 +93,6 @@ test_element.GetNameAttribute() == name_; } -bool RadioNodeList::CheckElementMatchesRadioNodeListFilter( - const Element& test_element) const { - DCHECK(!ShouldOnlyMatchImgElements()); - DCHECK(IsA<HTMLObjectElement>(test_element) || - test_element.IsFormControlElement()); - if (IsA<HTMLFormElement>(ownerNode())) { - auto* form_element = To<HTMLElement>(test_element).formOwner(); - if (!form_element || form_element != ownerNode()) - return false; - } - - return MatchesByIdOrName(test_element); -} - bool RadioNodeList::ElementMatches(const Element& element) const { if (ShouldOnlyMatchImgElements()) { auto* html_image_element = DynamicTo<HTMLImageElement>(element); @@ -117,16 +104,27 @@ return MatchesByIdOrName(element); } - - if (!IsA<HTMLObjectElement>(element) && !element.IsFormControlElement()) + auto* html_element = DynamicTo<HTMLElement>(element); + bool is_form_associated = + html_element && html_element->IsFormAssociatedCustomElement(); + if (!IsA<HTMLObjectElement>(element) && !element.IsFormControlElement() && + !is_form_associated) { return false; + } auto* html_input_element = DynamicTo<HTMLInputElement>(&element); if (html_input_element && - html_input_element->type() == input_type_names::kImage) + html_input_element->type() == input_type_names::kImage) { return false; + } - return CheckElementMatchesRadioNodeListFilter(element); + if (IsA<HTMLFormElement>(ownerNode())) { + auto* form_element = html_element->formOwner(); + if (!form_element || form_element != ownerNode()) + return false; + } + + return MatchesByIdOrName(element); } } // namespace blink
diff --git a/third_party/blink/renderer/core/html/forms/radio_node_list.h b/third_party/blink/renderer/core/html/forms/radio_node_list.h index d1a93ccb..fee9780 100644 --- a/third_party/blink/renderer/core/html/forms/radio_node_list.h +++ b/third_party/blink/renderer/core/html/forms/radio_node_list.h
@@ -45,8 +45,6 @@ void setValue(const String&); private: - bool CheckElementMatchesRadioNodeListFilter(const Element&) const; - bool MatchesByIdOrName(const Element&) const; bool ShouldOnlyMatchImgElements() const { return GetType() == kRadioImgNodeListType;
diff --git a/third_party/blink/renderer/core/html/html_element.cc b/third_party/blink/renderer/core/html/html_element.cc index ece92910..28f1d9a 100644 --- a/third_party/blink/renderer/core/html/html_element.cc +++ b/third_party/blink/renderer/core/html/html_element.cc
@@ -1077,6 +1077,12 @@ setAttribute(html_names::kDirAttr, value); } +HTMLFormElement* HTMLElement::formOwner() const { + if (const auto* internals = GetElementInternals()) + return internals->Form(); + return nullptr; +} + HTMLFormElement* HTMLElement::FindFormAncestor() const { return Traversal<HTMLFormElement>::FirstAncestor(*this); }
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h index d77acf8..f012bd45 100644 --- a/third_party/blink/renderer/core/html/html_element.h +++ b/third_party/blink/renderer/core/html/html_element.h
@@ -100,7 +100,7 @@ bool ShouldSerializeEndTag() const; - virtual HTMLFormElement* formOwner() const { return nullptr; } + virtual HTMLFormElement* formOwner() const; HTMLFormElement* FindFormAncestor() const;
diff --git a/third_party/blink/renderer/core/html/html_embed_element.idl b/third_party/blink/renderer/core/html/html_embed_element.idl index 5a94909..f8aa752 100644 --- a/third_party/blink/renderer/core/html/html_embed_element.idl +++ b/third_party/blink/renderer/core/html/html_embed_element.idl
@@ -20,10 +20,10 @@ // https://html.spec.whatwg.org/C/#the-embed-element -// TODO(yukishiino): HTMLEmbedElement should not have [LegacyOverrideBuiltins]. +// TODO(yukishiino): HTMLEmbedElement should not have [LegacyOverrideBuiltIns]. [ Exposed=Window, - LegacyOverrideBuiltins, + LegacyOverrideBuiltIns, ActiveScriptWrappable, HTMLConstructor ] interface HTMLEmbedElement : HTMLElement {
diff --git a/third_party/blink/renderer/core/html/html_frame_set_element.idl b/third_party/blink/renderer/core/html/html_frame_set_element.idl index a9a87cd..e76a621c 100644 --- a/third_party/blink/renderer/core/html/html_frame_set_element.idl +++ b/third_party/blink/renderer/core/html/html_frame_set_element.idl
@@ -20,11 +20,11 @@ // https://html.spec.whatwg.org/C/#htmlframesetelement -// FIXME: HTMLFrameSetElement should not have [LegacyOverrideBuiltins]. +// FIXME: HTMLFrameSetElement should not have [LegacyOverrideBuiltIns]. [ Exposed=Window, HTMLConstructor, - LegacyOverrideBuiltins + LegacyOverrideBuiltIns ] interface HTMLFrameSetElement : HTMLElement { [CEReactions, Reflect] attribute DOMString cols; [CEReactions, Reflect] attribute DOMString rows;
diff --git a/third_party/blink/renderer/core/html/html_object_element.idl b/third_party/blink/renderer/core/html/html_object_element.idl index a5b9d30..ec75bf3 100644 --- a/third_party/blink/renderer/core/html/html_object_element.idl +++ b/third_party/blink/renderer/core/html/html_object_element.idl
@@ -20,10 +20,10 @@ // https://html.spec.whatwg.org/C/#the-object-element -// TODO(yukishiino): HTMLObjectElement should not have [LegacyOverrideBuiltins]. +// TODO(yukishiino): HTMLObjectElement should not have [LegacyOverrideBuiltIns]. [ Exposed=Window, - LegacyOverrideBuiltins, + LegacyOverrideBuiltIns, ActiveScriptWrappable, HTMLConstructor ] interface HTMLObjectElement : HTMLElement {
diff --git a/third_party/blink/renderer/core/layout/layout_theme.cc b/third_party/blink/renderer/core/layout/layout_theme.cc index 9f198c1a..2db3a9f9 100644 --- a/third_party/blink/renderer/core/layout/layout_theme.cc +++ b/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -228,7 +228,7 @@ return part; } -void LayoutTheme::AdjustStyle(ComputedStyle& style, Element* e) { +void LayoutTheme::AdjustStyle(const Element* e, ComputedStyle& style) { ControlPart original_part = style.Appearance(); style.SetEffectiveAppearance(original_part); if (original_part == ControlPart::kNoControlPart) @@ -262,6 +262,9 @@ DCHECK_NE(part, kAutoPart); if (part == kNoControlPart) return; + DCHECK(e); + // After this point, a Node must be non-null Element if + // EffectiveAppearance() != kNoControlPart. AdjustControlPartStyle(style); @@ -269,14 +272,14 @@ // value. switch (part) { case kMenulistPart: - return AdjustMenuListStyle(style, e); + return AdjustMenuListStyle(style); case kMenulistButtonPart: - return AdjustMenuListButtonStyle(style, e); + return AdjustMenuListButtonStyle(style); case kSliderHorizontalPart: case kSliderVerticalPart: case kMediaSliderPart: case kMediaVolumeSliderPart: - return AdjustSliderContainerStyle(style, e); + return AdjustSliderContainerStyle(*e, style); case kSliderThumbHorizontalPart: case kSliderThumbVerticalPart: return AdjustSliderThumbStyle(style); @@ -469,20 +472,18 @@ void LayoutTheme::AdjustInnerSpinButtonStyle(ComputedStyle&) const {} -void LayoutTheme::AdjustMenuListStyle(ComputedStyle& style, Element*) const { +void LayoutTheme::AdjustMenuListStyle(ComputedStyle& style) const { // Menulists should have visible overflow // https://bugs.webkit.org/show_bug.cgi?id=21287 style.SetOverflowX(EOverflow::kVisible); style.SetOverflowY(EOverflow::kVisible); } -void LayoutTheme::AdjustMenuListButtonStyle(ComputedStyle&, Element*) const {} +void LayoutTheme::AdjustMenuListButtonStyle(ComputedStyle&) const {} -void LayoutTheme::AdjustSliderContainerStyle(ComputedStyle& style, - Element* e) const { - if (!e) - return; - const AtomicString& pseudo = e->ShadowPseudoId(); +void LayoutTheme::AdjustSliderContainerStyle(const Element& e, + ComputedStyle& style) const { + const AtomicString& pseudo = e.ShadowPseudoId(); if (pseudo != shadow_element_names::kPseudoMediaSliderContainer && pseudo != shadow_element_names::kPseudoSliderContainer) return;
diff --git a/third_party/blink/renderer/core/layout/layout_theme.h b/third_party/blink/renderer/core/layout/layout_theme.h index 110977e..27c0f97 100644 --- a/third_party/blink/renderer/core/layout/layout_theme.h +++ b/third_party/blink/renderer/core/layout/layout_theme.h
@@ -69,7 +69,7 @@ // selection of control size based off the font, the disabling of appearance // when certain other properties like "border" are set, or if the appearance // is not supported by the theme. - void AdjustStyle(ComputedStyle&, Element*); + void AdjustStyle(const Element*, ComputedStyle&); // The remaining methods should be implemented by the platform-specific // portion of the theme, e.g., LayoutThemeMac.cpp for Mac OS X. @@ -209,9 +209,9 @@ virtual void AdjustButtonStyle(ComputedStyle&) const; virtual void AdjustInnerSpinButtonStyle(ComputedStyle&) const; - virtual void AdjustMenuListStyle(ComputedStyle&, Element*) const; - virtual void AdjustMenuListButtonStyle(ComputedStyle&, Element*) const; - virtual void AdjustSliderContainerStyle(ComputedStyle&, Element*) const; + virtual void AdjustMenuListStyle(ComputedStyle&) const; + virtual void AdjustMenuListButtonStyle(ComputedStyle&) const; + virtual void AdjustSliderContainerStyle(const Element&, ComputedStyle&) const; virtual void AdjustSliderThumbStyle(ComputedStyle&) const; virtual void AdjustSearchFieldStyle(ComputedStyle&) const; virtual void AdjustSearchFieldCancelButtonStyle(ComputedStyle&) const;
diff --git a/third_party/blink/renderer/core/layout/layout_theme_default.cc b/third_party/blink/renderer/core/layout/layout_theme_default.cc index f26ad87..c5941c2 100644 --- a/third_party/blink/renderer/core/layout/layout_theme_default.cc +++ b/third_party/blink/renderer/core/layout/layout_theme_default.cc
@@ -238,16 +238,14 @@ style.SetHeight(Length::Fixed(cancel_button_size)); } -void LayoutThemeDefault::AdjustMenuListStyle(ComputedStyle& style, - Element* element) const { - LayoutTheme::AdjustMenuListStyle(style, element); +void LayoutThemeDefault::AdjustMenuListStyle(ComputedStyle& style) const { + LayoutTheme::AdjustMenuListStyle(style); // Height is locked to auto on all browsers. style.SetLineHeight(ComputedStyleInitialValues::InitialLineHeight()); } -void LayoutThemeDefault::AdjustMenuListButtonStyle(ComputedStyle& style, - Element* e) const { - AdjustMenuListStyle(style, e); +void LayoutThemeDefault::AdjustMenuListButtonStyle(ComputedStyle& style) const { + AdjustMenuListStyle(style); } // The following internal paddings are in addition to the user-supplied padding.
diff --git a/third_party/blink/renderer/core/layout/layout_theme_default.h b/third_party/blink/renderer/core/layout/layout_theme_default.h index d9864c07..ccdbbc00 100644 --- a/third_party/blink/renderer/core/layout/layout_theme_default.h +++ b/third_party/blink/renderer/core/layout/layout_theme_default.h
@@ -80,8 +80,8 @@ // In short, we either go down the MenuList code path or the MenuListButton // codepath. We never go down both. And in both cases, they layout the // entire menulist. - void AdjustMenuListStyle(ComputedStyle&, Element*) const override; - void AdjustMenuListButtonStyle(ComputedStyle&, Element*) const override; + void AdjustMenuListStyle(ComputedStyle&) const override; + void AdjustMenuListButtonStyle(ComputedStyle&) const override; // These methods define the padding for the MenuList's inner block. int PopupInternalPaddingStart(const ComputedStyle&) const override;
diff --git a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc index 1448479..4f08a9f 100644 --- a/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc +++ b/third_party/blink/renderer/core/loader/frame_fetch_context_test.cc
@@ -35,6 +35,7 @@ #include "base/optional.h" #include "base/test/scoped_feature_list.h" #include "build/build_config.h" +#include "services/network/public/cpp/features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/common/device_memory/approximated_device_memory.h" @@ -550,6 +551,9 @@ } TEST_F(FrameFetchContextModifyRequestTest, SendRequiredCSPHeader) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndDisableFeature(network::features::kOutOfBlinkCSPEE); + struct TestCase { const char* to_request; mojom::RequestContextFrameType frame_type;
diff --git a/third_party/blink/renderer/core/paint/theme_painter.cc b/third_party/blink/renderer/core/paint/theme_painter.cc index abfbc0f..20c295f2 100644 --- a/third_party/blink/renderer/core/paint/theme_painter.cc +++ b/third_party/blink/renderer/core/paint/theme_painter.cc
@@ -67,19 +67,18 @@ #define COUNT_APPEARANCE(doc, feature) \ doc.CountUse(WebFeature::kCSSValueAppearance##feature##Rendered) -void CountAppearanceTextFieldPart(const Node* node) { - DCHECK(node); - if (auto* input = DynamicTo<HTMLInputElement>(node)) { +void CountAppearanceTextFieldPart(const Element& element) { + if (auto* input = DynamicTo<HTMLInputElement>(element)) { const AtomicString& type = input->type(); if (type == input_type_names::kSearch) { - UseCounter::Count(node->GetDocument(), + UseCounter::Count(element.GetDocument(), WebFeature::kCSSValueAppearanceTextFieldForSearch); } else if (input->IsTextField()) { - UseCounter::Count(node->GetDocument(), + UseCounter::Count(element.GetDocument(), WebFeature::kCSSValueAppearanceTextFieldForTextField); } else if (IsMultipleFieldsTemporalInput(type)) { UseCounter::Count( - node->GetDocument(), + element.GetDocument(), WebFeature::kCSSValueAppearanceTextFieldForTemporalRendered); } } @@ -89,26 +88,27 @@ bool ThemePainter::Paint(const LayoutObject& o, const PaintInfo& paint_info, const IntRect& r) { - const Node* node = o.GetNode(); Document& doc = o.GetDocument(); const ComputedStyle& style = o.StyleRef(); ControlPart part = o.StyleRef().EffectiveAppearance(); // LayoutTheme::AdjustAppearanceWithElementType() ensures |node| is a // non-null Element. - DCHECK(node); + DCHECK(o.GetNode()); DCHECK_NE(part, kNoControlPart); + const Element& element = *To<Element>(o.GetNode()); if (part == kButtonPart) { - if (IsA<HTMLButtonElement>(node)) { + if (IsA<HTMLButtonElement>(element)) { UseCounter::Count(doc, WebFeature::kCSSValueAppearanceButtonForButton); - } else if (IsA<HTMLInputElement>(node) && - To<HTMLInputElement>(node)->IsTextButton()) { + } else if (IsA<HTMLInputElement>(element) && + To<HTMLInputElement>(element).IsTextButton()) { // Text buttons (type=button, reset, submit) has // -webkit-appearance:push-button by default. UseCounter::Count(doc, WebFeature::kCSSValueAppearanceButtonForOtherButtons); - } else if (IsA<HTMLInputElement>(node) && - To<HTMLInputElement>(node)->type() == input_type_names::kColor) { + } else if (IsA<HTMLInputElement>(element) && + To<HTMLInputElement>(element).type() == + input_type_names::kColor) { // 'button' for input[type=color], of which default appearance is // 'square-button', is not deprecated. } @@ -118,51 +118,51 @@ switch (part) { case kCheckboxPart: { COUNT_APPEARANCE(doc, Checkbox); - return PaintCheckbox(node, o.GetDocument(), style, paint_info, r); + return PaintCheckbox(element, o.GetDocument(), style, paint_info, r); } case kRadioPart: { COUNT_APPEARANCE(doc, Radio); - return PaintRadio(node, o.GetDocument(), style, paint_info, r); + return PaintRadio(element, o.GetDocument(), style, paint_info, r); } case kPushButtonPart: { COUNT_APPEARANCE(doc, PushButton); - return PaintButton(node, o.GetDocument(), style, paint_info, r); + return PaintButton(element, o.GetDocument(), style, paint_info, r); } case kSquareButtonPart: { COUNT_APPEARANCE(doc, SquareButton); - return PaintButton(node, o.GetDocument(), style, paint_info, r); + return PaintButton(element, o.GetDocument(), style, paint_info, r); } case kButtonPart: // UseCounter for this is handled at the beginning of the function. - return PaintButton(node, o.GetDocument(), style, paint_info, r); + return PaintButton(element, o.GetDocument(), style, paint_info, r); case kInnerSpinButtonPart: { COUNT_APPEARANCE(doc, InnerSpinButton); - return PaintInnerSpinButton(node, style, paint_info, r); + return PaintInnerSpinButton(element, style, paint_info, r); } case kMenulistPart: COUNT_APPEARANCE(doc, MenuList); - return PaintMenuList(node, o.GetDocument(), style, paint_info, r); + return PaintMenuList(element, o.GetDocument(), style, paint_info, r); case kMeterPart: return true; case kProgressBarPart: COUNT_APPEARANCE(doc, ProgressBar); // Note that |-webkit-appearance: progress-bar| works only for <progress>. - return PaintProgressBar(o, paint_info, r); + return PaintProgressBar(element, o, paint_info, r); case kSliderHorizontalPart: { COUNT_APPEARANCE(doc, SliderHorizontal); - return PaintSliderTrack(o, paint_info, r); + return PaintSliderTrack(element, o, paint_info, r); } case kSliderVerticalPart: { COUNT_APPEARANCE(doc, SliderVertical); - return PaintSliderTrack(o, paint_info, r); + return PaintSliderTrack(element, o, paint_info, r); } case kSliderThumbHorizontalPart: { COUNT_APPEARANCE(doc, SliderThumbHorizontal); - return PaintSliderThumb(node, style, paint_info, r); + return PaintSliderThumb(element, style, paint_info, r); } case kSliderThumbVerticalPart: { COUNT_APPEARANCE(doc, SliderThumbVertical); - return PaintSliderThumb(node, style, paint_info, r); + return PaintSliderThumb(element, style, paint_info, r); } case kMediaSliderPart: case kMediaSliderThumbPart: @@ -175,17 +175,17 @@ if (!features::IsFormControlsRefreshEnabled()) { return true; } - CountAppearanceTextFieldPart(node); - return PaintTextField(node, style, paint_info, r); + CountAppearanceTextFieldPart(element); + return PaintTextField(element, style, paint_info, r); case kTextAreaPart: if (!features::IsFormControlsRefreshEnabled()) { return true; } COUNT_APPEARANCE(doc, TextArea); - return PaintTextArea(node, style, paint_info, r); + return PaintTextArea(element, style, paint_info, r); case kSearchFieldPart: { COUNT_APPEARANCE(doc, SearchField); - return PaintSearchField(node, style, paint_info, r); + return PaintSearchField(element, style, paint_info, r); } case kSearchFieldCancelButtonPart: { COUNT_APPEARANCE(doc, SearchCancel); @@ -206,20 +206,23 @@ const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& r) { + DCHECK(style.HasEffectiveAppearance()); + DCHECK(node); + const Element& element = *To<Element>(node); // Call the appropriate paint method based off the appearance value. switch (style.EffectiveAppearance()) { case kTextFieldPart: if (features::IsFormControlsRefreshEnabled()) { return false; } - CountAppearanceTextFieldPart(node); - return PaintTextField(node, style, paint_info, r); + CountAppearanceTextFieldPart(element); + return PaintTextField(element, style, paint_info, r); case kTextAreaPart: if (features::IsFormControlsRefreshEnabled()) { return false; } - COUNT_APPEARANCE(node->GetDocument(), TextArea); - return PaintTextArea(node, style, paint_info, r); + COUNT_APPEARANCE(element.GetDocument(), TextArea); + return PaintTextArea(element, style, paint_info, r); case kMenulistButtonPart: case kSearchFieldPart: case kListboxPart: @@ -241,7 +244,7 @@ return false; default: UseCounter::Count( - node->GetDocument(), + element.GetDocument(), WebFeature::kCSSValueAppearanceNoImplementationSkipBorder); // TODO(tkent): Should do CSS border painting for non-supported // appearance values. @@ -256,11 +259,13 @@ const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& r) { + DCHECK(node); // Call the appropriate paint method based off the appearance value. switch (style.EffectiveAppearance()) { case kMenulistButtonPart: COUNT_APPEARANCE(document, MenuListButton); - return PaintMenuListButton(node, document, style, paint_info, r); + return PaintMenuListButton(*To<Element>(node), document, style, + paint_info, r); case kTextFieldPart: case kTextAreaPart: case kCheckboxPart:
diff --git a/third_party/blink/renderer/core/paint/theme_painter.h b/third_party/blink/renderer/core/paint/theme_painter.h index 1c563c35..de2ef35 100644 --- a/third_party/blink/renderer/core/paint/theme_painter.h +++ b/third_party/blink/renderer/core/paint/theme_painter.h
@@ -30,6 +30,7 @@ class ComputedStyle; class Document; +class Element; class IntRect; class LayoutObject; class Node; @@ -64,76 +65,78 @@ void PaintSliderTicks(const LayoutObject&, const PaintInfo&, const IntRect&); protected: - virtual bool PaintCheckbox(const Node*, + virtual bool PaintCheckbox(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintRadio(const Node*, + virtual bool PaintRadio(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintButton(const Node*, + virtual bool PaintButton(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintInnerSpinButton(const Node*, + virtual bool PaintInnerSpinButton(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintTextField(const Node*, + virtual bool PaintTextField(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintTextArea(const Node*, + virtual bool PaintTextArea(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintMenuList(const Node*, + virtual bool PaintMenuList(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintMenuListButton(const Node* node, + virtual bool PaintMenuListButton(const Element& element, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintProgressBar(const LayoutObject&, + virtual bool PaintProgressBar(const Element& element, + const LayoutObject&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintSliderTrack(const LayoutObject&, + virtual bool PaintSliderTrack(const Element& element, + const LayoutObject&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintSliderThumb(const Node*, + virtual bool PaintSliderThumb(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) { return true; } - virtual bool PaintSearchField(const Node*, + virtual bool PaintSearchField(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) {
diff --git a/third_party/blink/renderer/core/paint/theme_painter_default.cc b/third_party/blink/renderer/core/paint/theme_painter_default.cc index 8605f9a..8c19781 100644 --- a/third_party/blink/renderer/core/paint/theme_painter_default.cc +++ b/third_party/blink/renderer/core/paint/theme_painter_default.cc
@@ -47,38 +47,24 @@ const unsigned kDefaultButtonBackgroundColor = 0xffdddddd; -bool IsDisabled(const Node* node) { - if (const auto* element = DynamicTo<Element>(node)) - return element->IsDisabledFormControl(); +bool IsIndeterminate(const Element& element) { + if (const auto* input = DynamicTo<HTMLInputElement>(element)) + return input->ShouldAppearIndeterminate(); return false; } -bool IsPressed(const Node* node) { - return node && node->IsActive(); -} - -bool IsHovered(const Node* node) { - return node && node->IsHovered(); -} - -bool IsIndeterminate(const Node* node) { - if (const auto* element = DynamicTo<HTMLInputElement>(node)) - return element->ShouldAppearIndeterminate(); - return false; -} - -bool IsChecked(const Node* node) { - if (auto* input = DynamicTo<HTMLInputElement>(node)) +bool IsChecked(const Element& element) { + if (const auto* input = DynamicTo<HTMLInputElement>(element)) return input->ShouldAppearChecked(); return false; } -WebThemeEngine::State GetWebThemeState(const Node* node) { - if (IsDisabled(node)) +WebThemeEngine::State GetWebThemeState(const Element& element) { + if (element.IsDisabledFormControl()) return WebThemeEngine::kStateDisabled; - if (IsPressed(node)) + if (element.IsActive()) return WebThemeEngine::kStatePressed; - if (IsHovered(node)) + if (element.IsHovered()) return WebThemeEngine::kStateHover; return WebThemeEngine::kStateNormal; @@ -164,7 +150,7 @@ ThemePainterDefault::ThemePainterDefault(LayoutThemeDefault& theme) : ThemePainter(), theme_(theme) {} -bool ThemePainterDefault::PaintCheckbox(const Node* node, +bool ThemePainterDefault::PaintCheckbox(const Element& element, const Document&, const ComputedStyle& style, const PaintInfo& paint_info, @@ -172,8 +158,8 @@ WebThemeEngine::ExtraParams extra_params; cc::PaintCanvas* canvas = paint_info.context.Canvas(); extra_params.button = WebThemeEngine::ButtonExtraParams(); - extra_params.button.checked = IsChecked(node); - extra_params.button.indeterminate = IsIndeterminate(node); + extra_params.button.checked = IsChecked(element); + extra_params.button.indeterminate = IsIndeterminate(element); float zoom_level = style.EffectiveZoom(); extra_params.button.zoom = zoom_level; @@ -189,12 +175,12 @@ } Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartCheckbox, GetWebThemeState(node), + canvas, WebThemeEngine::kPartCheckbox, GetWebThemeState(element), WebRect(unzoomed_rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintRadio(const Node* node, +bool ThemePainterDefault::PaintRadio(const Element& element, const Document&, const ComputedStyle& style, const PaintInfo& paint_info, @@ -202,15 +188,15 @@ WebThemeEngine::ExtraParams extra_params; cc::PaintCanvas* canvas = paint_info.context.Canvas(); extra_params.button = WebThemeEngine::ButtonExtraParams(); - extra_params.button.checked = IsChecked(node); + extra_params.button.checked = IsChecked(element); Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartRadio, GetWebThemeState(node), WebRect(rect), - &extra_params, style.UsedColorScheme()); + canvas, WebThemeEngine::kPartRadio, GetWebThemeState(element), + WebRect(rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintButton(const Node* node, +bool ThemePainterDefault::PaintButton(const Element& element, const Document&, const ComputedStyle& style, const PaintInfo& paint_info, @@ -225,12 +211,12 @@ style.VisitedDependentColor(GetCSSPropertyBackgroundColor()).Rgb(); } Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartButton, GetWebThemeState(node), + canvas, WebThemeEngine::kPartButton, GetWebThemeState(element), WebRect(rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintTextField(const Node* node, +bool ThemePainterDefault::PaintTextField(const Element& element, const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& rect) { @@ -262,15 +248,15 @@ style.VisitedDependentColor(GetCSSPropertyBackgroundColor()); extra_params.text_field.background_color = background_color.Rgb(); extra_params.text_field.auto_complete_active = - DynamicTo<HTMLFormControlElement>(node)->IsAutofilled(); + DynamicTo<HTMLFormControlElement>(element)->IsAutofilled(); Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartTextField, GetWebThemeState(node), + canvas, WebThemeEngine::kPartTextField, GetWebThemeState(element), WebRect(rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintMenuList(const Node* node, +bool ThemePainterDefault::PaintMenuList(const Element& element, const Document& document, const ComputedStyle& style, const PaintInfo& i, @@ -299,12 +285,12 @@ cc::PaintCanvas* canvas = i.context.Canvas(); Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartMenuList, GetWebThemeState(node), + canvas, WebThemeEngine::kPartMenuList, GetWebThemeState(element), WebRect(rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintMenuListButton(const Node* node, +bool ThemePainterDefault::PaintMenuListButton(const Element& element, const Document& document, const ComputedStyle& style, const PaintInfo& paint_info, @@ -318,7 +304,7 @@ cc::PaintCanvas* canvas = paint_info.context.Canvas(); Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartMenuList, GetWebThemeState(node), + canvas, WebThemeEngine::kPartMenuList, GetWebThemeState(element), WebRect(rect), &extra_params, style.UsedColorScheme()); return false; } @@ -350,7 +336,8 @@ style.VisitedDependentColor(GetCSSPropertyColor()).Rgb(); } -bool ThemePainterDefault::PaintSliderTrack(const LayoutObject& o, +bool ThemePainterDefault::PaintSliderTrack(const Element& element, + const LayoutObject& o, const PaintInfo& i, const IntRect& rect) { WebThemeEngine::ExtraParams extra_params; @@ -374,7 +361,7 @@ i.context.Translate(-unzoomed_rect.X(), -unzoomed_rect.Y()); } - auto* input = DynamicTo<HTMLInputElement>(o.GetNode()); + auto* input = DynamicTo<HTMLInputElement>(element); extra_params.slider.thumb_x = 0; extra_params.slider.thumb_y = 0; extra_params.slider.right_to_left = !o.StyleRef().IsLeftToRightDirection(); @@ -408,12 +395,12 @@ } Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartSliderTrack, GetWebThemeState(o.GetNode()), + canvas, WebThemeEngine::kPartSliderTrack, GetWebThemeState(element), WebRect(unzoomed_rect), &extra_params, o.StyleRef().UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintSliderThumb(const Node* node, +bool ThemePainterDefault::PaintSliderThumb(const Element& element, const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& rect) { @@ -421,7 +408,7 @@ cc::PaintCanvas* canvas = paint_info.context.Canvas(); extra_params.slider.vertical = style.EffectiveAppearance() == kSliderThumbVerticalPart; - extra_params.slider.in_drag = IsPressed(node); + extra_params.slider.in_drag = element.IsActive(); float zoom_level = style.EffectiveZoom(); extra_params.slider.zoom = zoom_level; @@ -437,12 +424,12 @@ } Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartSliderThumb, GetWebThemeState(node), + canvas, WebThemeEngine::kPartSliderThumb, GetWebThemeState(element), WebRect(unzoomed_rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintInnerSpinButton(const Node* node, +bool ThemePainterDefault::PaintInnerSpinButton(const Element& element, const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& rect) { @@ -450,25 +437,26 @@ cc::PaintCanvas* canvas = paint_info.context.Canvas(); bool spin_up = false; - if (const auto* element = DynamicTo<SpinButtonElement>(node)) { - if (element->GetUpDownState() == SpinButtonElement::kUp) - spin_up = node->IsHovered() || node->IsActive(); + if (const auto* spin_buttom = DynamicTo<SpinButtonElement>(element)) { + if (spin_buttom->GetUpDownState() == SpinButtonElement::kUp) + spin_up = element.IsHovered() || element.IsActive(); } bool read_only = false; - if (const auto* element = DynamicTo<HTMLFormControlElement>(node)) - read_only = element->IsReadOnly(); + if (const auto* control = DynamicTo<HTMLFormControlElement>(element)) + read_only = control->IsReadOnly(); extra_params.inner_spin.spin_up = spin_up; extra_params.inner_spin.read_only = read_only; Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartInnerSpinButton, GetWebThemeState(node), + canvas, WebThemeEngine::kPartInnerSpinButton, GetWebThemeState(element), WebRect(rect), &extra_params, style.UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintProgressBar(const LayoutObject& o, +bool ThemePainterDefault::PaintProgressBar(const Element& element, + const LayoutObject& o, const PaintInfo& i, const IntRect& rect) { if (!o.IsProgress()) @@ -487,23 +475,23 @@ DirectionFlippingScope scope(o, i, rect); cc::PaintCanvas* canvas = i.context.Canvas(); Platform::Current()->ThemeEngine()->Paint( - canvas, WebThemeEngine::kPartProgressBar, GetWebThemeState(o.GetNode()), + canvas, WebThemeEngine::kPartProgressBar, GetWebThemeState(element), WebRect(rect), &extra_params, o.StyleRef().UsedColorScheme()); return false; } -bool ThemePainterDefault::PaintTextArea(const Node* node, +bool ThemePainterDefault::PaintTextArea(const Element& element, const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& rect) { - return PaintTextField(node, style, paint_info, rect); + return PaintTextField(element, style, paint_info, rect); } -bool ThemePainterDefault::PaintSearchField(const Node* node, +bool ThemePainterDefault::PaintSearchField(const Element& element, const ComputedStyle& style, const PaintInfo& paint_info, const IntRect& rect) { - return PaintTextField(node, style, paint_info, rect); + return PaintTextField(element, style, paint_info, rect); } bool ThemePainterDefault::PaintSearchFieldCancelButton( @@ -511,8 +499,6 @@ const PaintInfo& paint_info, const IntRect& r) { // Get the layoutObject of <input> element. - if (!cancel_button_object.GetNode()) - return false; Node* input = cancel_button_object.GetNode()->OwnerShadowHost(); const LayoutObject& base_layout_object = input && input->GetLayoutObject() ? *input->GetLayoutObject() @@ -553,10 +539,11 @@ Image* color_scheme_adjusted_cancel_pressed_image = color_scheme == kLight ? cancel_pressed_image : cancel_pressed_image_dark_mode; - paint_info.context.DrawImage(IsPressed(cancel_button_object.GetNode()) - ? color_scheme_adjusted_cancel_pressed_image - : color_scheme_adjusted_cancel_image, - Image::kSyncDecode, FloatRect(painting_rect)); + paint_info.context.DrawImage( + To<Element>(cancel_button_object.GetNode())->IsActive() + ? color_scheme_adjusted_cancel_pressed_image + : color_scheme_adjusted_cancel_image, + Image::kSyncDecode, FloatRect(painting_rect)); return false; }
diff --git a/third_party/blink/renderer/core/paint/theme_painter_default.h b/third_party/blink/renderer/core/paint/theme_painter_default.h index ffa9afb..344b6686 100644 --- a/third_party/blink/renderer/core/paint/theme_painter_default.h +++ b/third_party/blink/renderer/core/paint/theme_painter_default.h
@@ -41,54 +41,56 @@ explicit ThemePainterDefault(LayoutThemeDefault&); private: - bool PaintCheckbox(const Node*, + bool PaintCheckbox(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintRadio(const Node*, + bool PaintRadio(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintButton(const Node*, + bool PaintButton(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintTextField(const Node*, + bool PaintTextField(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintMenuList(const Node*, + bool PaintMenuList(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintMenuListButton(const Node*, + bool PaintMenuListButton(const Element&, const Document&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintSliderTrack(const LayoutObject&, + bool PaintSliderTrack(const Element& element, + const LayoutObject&, const PaintInfo&, const IntRect&) override; - bool PaintSliderThumb(const Node*, + bool PaintSliderThumb(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintInnerSpinButton(const Node*, + bool PaintInnerSpinButton(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintProgressBar(const LayoutObject&, + bool PaintProgressBar(const Element& element, + const LayoutObject&, const PaintInfo&, const IntRect&) override; - bool PaintTextArea(const Node*, + bool PaintTextArea(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) override; - bool PaintSearchField(const Node*, + bool PaintSearchField(const Element&, const ComputedStyle&, const PaintInfo&, const IntRect&) override;
diff --git a/third_party/blink/renderer/modules/BUILD.gn b/third_party/blink/renderer/modules/BUILD.gn index f3641ca..244cbcf 100644 --- a/third_party/blink/renderer/modules/BUILD.gn +++ b/third_party/blink/renderer/modules/BUILD.gn
@@ -245,9 +245,11 @@ "//third_party/blink/renderer/core:blink_core_pch", ] + public_deps = [ "//testing/gmock:gmock" ] deps = [ "//third_party/blink/renderer/bindings/modules/v8:testing", "//third_party/blink/renderer/core", + "//third_party/blink/renderer/core:testing", "//third_party/blink/renderer/modules", ] } @@ -496,23 +498,34 @@ "//components/schema_org/common:mojom_blink", "//media:test_support", "//media/mojo/mojom", + "//media/webrtc:webrtc", "//mojo/public/cpp/bindings", "//net:quic_test_tools", + "//net:test_support", "//services/device/public/cpp:test_support", "//skia", "//testing/gmock", "//testing/gtest", "//third_party/blink/public:blink_headers", + "//third_party/blink/public:test_headers", + "//third_party/blink/public/strings:strings_grit", + "//third_party/blink/renderer/controller:blink_bindings_test_sources", "//third_party/blink/renderer/core", + "//third_party/blink/renderer/core:testing", "//third_party/blink/renderer/core:unit_test_support", "//third_party/blink/renderer/modules/gamepad:unit_tests", "//third_party/blink/renderer/modules/hid:unit_tests", + "//third_party/blink/renderer/modules/mediarecorder:buildflags", + "//third_party/blink/renderer/modules/mediastream:test_support", "//third_party/blink/renderer/modules/native_file_system:unit_tests", + "//third_party/blink/renderer/modules/peerconnection:test_support", "//third_party/blink/renderer/modules/storage:unit_tests", "//third_party/blink/renderer/modules/webcodecs:unit_tests", "//third_party/blink/renderer/modules/webtransport:unit_tests", "//third_party/blink/renderer/platform", + "//third_party/blink/renderer/platform:test_support", "//third_party/blink/renderer/platform/wtf", + "//third_party/googletest:gmock", "//third_party/opus", "//third_party/webrtc_overrides:webrtc_component", "//v8", @@ -552,6 +565,7 @@ deps = [ ":modules", + "//third_party/blink/renderer/core:testing", "//third_party/blink/renderer/modules/media_capabilities:fuzzer_media_configuration_proto", "//third_party/blink/renderer/platform:blink_fuzzer_test_support", "//third_party/libprotobuf-mutator", @@ -570,6 +584,7 @@ deps = [ ":modules", + "//third_party/blink/renderer/core:testing", "//third_party/blink/renderer/modules/webcodecs:fuzzer_protos", "//third_party/blink/renderer/platform:blink_fuzzer_test_support", "//third_party/libprotobuf-mutator", @@ -588,6 +603,7 @@ deps = [ ":modules", + "//third_party/blink/renderer/core:testing", "//third_party/blink/renderer/modules/webcodecs:fuzzer_protos", "//third_party/blink/renderer/platform:blink_fuzzer_test_support", "//third_party/libprotobuf-mutator", @@ -606,6 +622,7 @@ deps = [ ":modules", + "//third_party/blink/renderer/core:testing", "//third_party/blink/renderer/modules/webcodecs:fuzzer_protos", "//third_party/blink/renderer/platform:blink_fuzzer_test_support", "//third_party/libprotobuf-mutator",
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object.cc b/third_party/blink/renderer/modules/accessibility/ax_object.cc index c5f9949..de9daa1e 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_object.cc
@@ -3621,9 +3621,16 @@ AXObjectCache().GetDocument().GetFrame()->View(); IntRect root_frame_rect = root_view->FrameToScreen(root_view->FrameRect()); + + // Screen coordinates are in DIP without device scale factor applied. + // Accessibility expects device scale factor applied here which is + // unapplied at the destination AXTree. + float scale_factor = + view->GetPage()->GetChromeClient().WindowToViewportScalar( + layout_object->GetFrame(), 1.0f); out_bounds_in_container.SetLocation( - FloatPoint(frame_rect.X() - root_frame_rect.X(), - frame_rect.Y() - root_frame_rect.Y())); + FloatPoint(scale_factor * (frame_rect.X() - root_frame_rect.X()), + scale_factor * (frame_rect.Y() - root_frame_rect.Y()))); } } return;
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn index b4d5d56..43823db0 100644 --- a/third_party/blink/renderer/platform/BUILD.gn +++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1736,6 +1736,7 @@ sources = [ "graphics/gpu/drawing_buffer_test_helpers.h", "graphics/paint/paint_controller_test.h", + "graphics/test/fake_canvas_resource_host.h", "graphics/test/fake_gles2_interface.h", "graphics/test/fake_web_graphics_context_3d_provider.h", "graphics/test/gpu_memory_buffer_test_platform.h", @@ -2404,7 +2405,6 @@ "graphics/image_decoding_store_test.cc", "graphics/image_frame_generator_test.cc", "graphics/paint_worklet_paint_dispatcher_test.cc", - "graphics/test/fake_canvas_resource_host.h", "graphics/test/stub_image.h", # Tests migrated from the web/tests directory.
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc index dc518d6..bcd37c2 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.cc
@@ -1242,7 +1242,7 @@ } std::unique_ptr<WebURLLoader> ResourceFetcher::CreateURLLoader( - const ResourceRequest& request, + const ResourceRequestHead& request, const ResourceLoaderOptions& options) { DCHECK(!GetProperties().IsDetached()); DCHECK(loader_factory_); @@ -1253,9 +1253,13 @@ new_options.url_loader_factory = base::MakeRefCounted<base::RefCountedData< mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>>>( bundle->GetURLLoaderFactory()); - return loader_factory_->CreateURLLoader(request, new_options, task_runner_); + // TODO(yoichio): CreateURLLoader take a ResourceRequestHead instead of + // ResourceRequest. + return loader_factory_->CreateURLLoader(ResourceRequest(request), + new_options, task_runner_); } - return loader_factory_->CreateURLLoader(request, options, task_runner_); + return loader_factory_->CreateURLLoader(ResourceRequest(request), options, + task_runner_); } std::unique_ptr<WebCodeCacheLoader> ResourceFetcher::CreateCodeCacheLoader() {
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h index 224915c..de7d229f5c 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h +++ b/third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h
@@ -157,7 +157,7 @@ } // Create a loader. This cannot be called after ClearContext is called. - std::unique_ptr<WebURLLoader> CreateURLLoader(const ResourceRequest&, + std::unique_ptr<WebURLLoader> CreateURLLoader(const ResourceRequestHead&, const ResourceLoaderOptions&); // Create a code cache loader. This cannot be called after ClearContext is // called.
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc index 9361628b..8b18458 100644 --- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc +++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -470,10 +470,7 @@ void ResourceLoader::Start() { const ResourceRequestHead& request = resource_->GetResourceRequest(); ActivateCacheAwareLoadingIfNeeded(request); - // TODO(yoichio): Have CreateURLLoader take a ResourceRequestHead, not - // ResourceRequest. - loader_ = - fetcher_->CreateURLLoader(ResourceRequest(request), resource_->Options()); + loader_ = fetcher_->CreateURLLoader(request, resource_->Options()); task_runner_for_body_loader_ = loader_->GetTaskRunner(); DCHECK_EQ(ResourceLoadScheduler::kInvalidClientId, scheduler_client_id_); auto throttle_option = ResourceLoadScheduler::ThrottleOption::kThrottleable; @@ -611,8 +608,7 @@ void ResourceLoader::Restart(const ResourceRequestHead& request) { CHECK_EQ(resource_->Options().synchronous_policy, kRequestAsynchronously); - loader_ = - fetcher_->CreateURLLoader(ResourceRequest(request), resource_->Options()); + loader_ = fetcher_->CreateURLLoader(request, resource_->Options()); task_runner_for_body_loader_ = loader_->GetTaskRunner(); StartWith(request); }
diff --git a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc index 64109c9..936a3cd 100644 --- a/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc +++ b/third_party/blink/renderer/platform/video_capture/video_capture_impl.cc
@@ -142,7 +142,8 @@ if (buffer_context->gmb_resources_->mailbox.IsZero()) { uint32_t usage = gpu::SHARED_IMAGE_USAGE_GLES2 | gpu::SHARED_IMAGE_USAGE_RASTER | - gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT; + gpu::SHARED_IMAGE_USAGE_DISPLAY | gpu::SHARED_IMAGE_USAGE_SCANOUT | + gpu::SHARED_IMAGE_USAGE_MACOS_VIDEO_TOOLBOX; buffer_context->gmb_resources_->mailbox = sii->CreateSharedImage( gpu_memory_buffer.get(), buffer_context->gpu_factories_->GpuMemoryBufferManager(),
diff --git a/third_party/blink/renderer/platform/wtf/linked_hash_set.h b/third_party/blink/renderer/platform/wtf/linked_hash_set.h index 5fb29f8b..2c6ad3c 100644 --- a/third_party/blink/renderer/platform/wtf/linked_hash_set.h +++ b/third_party/blink/renderer/platform/wtf/linked_hash_set.h
@@ -328,12 +328,13 @@ template <typename T, typename TraitsArg, typename Allocator> inline void LinkedHashSet<T, TraitsArg, Allocator>::erase(const_iterator it) { + if (it == end()) + return; + // Forbid GC while modifying LinkedHashSet to avoid conflict between // |value_to_index_| and |list_|. auto scope = GCForbiddenScope(); - if (it == end()) - return; value_to_index_.erase(*it); list_.erase(it.iterator_); }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index aa0df07..2653508 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -2921,7 +2921,7 @@ crbug.com/626703 external/wpt/speech-api/SpeechSynthesis-pause-resume.tentative.html [ Timeout ] crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-001.html [ Failure ] crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-interpolation-002.html [ Failure ] -crbug.com/626703 external/wpt/css/css-scrollbars/textarea-scrollbar-width-none.html [ Failure ] +crbug.com/891944 external/wpt/css/css-scrollbars/textarea-scrollbar-width-none.html [ Failure ] crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-002.html [ Failure ] crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-001.html [ Failure ] crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-local-mask.html [ Failure ]
diff --git a/third_party/blink/web_tests/VirtualTestSuites b/third_party/blink/web_tests/VirtualTestSuites index 205860b..f62870f 100644 --- a/third_party/blink/web_tests/VirtualTestSuites +++ b/third_party/blink/web_tests/VirtualTestSuites
@@ -704,7 +704,7 @@ { "prefix": "out-of-blink-cspee", "bases": [ "external/wpt/content-security-policy/embedded-enforcement" ], - "args": [ "--enable-features=OutOfBlinkCSPEE" ] + "args": [ "--disable-features=OutOfBlinkCSPEE" ] }, { "prefix": "subresource-web-bundles-disabled",
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json index ea40784..b7a49a5 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_8.json
@@ -147457,6 +147457,19 @@ ] }, "images": { + "blocked-by-csp.html": [ + "2416e5dfd089baba6716b4f2393e3dc86e242519", + [ + null, + [ + [ + "/html/rendering/replaced-elements/images/blocked-by-csp-ref.html", + "==" + ] + ], + {} + ] + ], "space.html": [ "fee115dfce6a0cf03069b6a24e8cb3149446a5ad", [ @@ -214412,6 +214425,10 @@ "9b2e5be0a19c48f73b57fe0ad8bbeea81238a1d1", [] ], + "blocked-by-csp-ref.html": [ + "f37d8a3ec94834673a75749a28a42638f9c2a0db", + [] + ], "space-ref.html": [ "0cf272e16211098b6020d5d15d0d71336ba88a59", [] @@ -221649,7 +221666,7 @@ [] ], "box-comparison.js": [ - "a574b01706b5fecc232d62735ef7e89938594769", + "b30ad279dfeba991a7e1f309b729d08e80638306", [] ], "box-navigation.js": [ @@ -295754,6 +295771,78 @@ {} ] ], + "parsing": { + "attribute.html": [ + "a8fcfb24f5a9b1350adda6e59af814f1111325c1", + [ + null, + {} + ] + ], + "child.html": [ + "510c45db867e978fc54d3b66f705d18acbf2aff8", + [ + null, + {} + ] + ], + "class.html": [ + "00abcf838da18641d96c9381da77d38365329356", + [ + null, + {} + ] + ], + "descendant.html": [ + "5ff3a7bbfd973a88a30d1c804347403e1df57562", + [ + null, + {} + ] + ], + "id.html": [ + "2441c4217eb4b9ef1c8bde1aa5a96269b09b6304", + [ + null, + {} + ] + ], + "is.html": [ + "68236445c5f1e871cd4e0c500057b2ad11955b60", + [ + null, + {} + ] + ], + "not.html": [ + "3895683d1c84c1a39a38f2976f7b672a2b06e121", + [ + null, + {} + ] + ], + "sibling.html": [ + "4f7a7a3fbcc14d20282a7eee5ab4f9dd768467bb", + [ + null, + {} + ] + ], + "universal.html": [ + "e944a93f12c0eafc9c19a2e827d93eb4448984e0", + [ + null, + {} + ] + ], + "where.html": [ + "3a90969570925fd85df07508a76baa02dc1ec5b6", + [ + null, + {} + ] + ] + }, "pseudo-enabled-disabled.html": [ "521767de3763130f22e066c01d38fb7e83cb3de9", [
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/attribute.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/attribute.html new file mode 100644 index 0000000..a8fcfb2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/attribute.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: Attribute selectors</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#attribute-selectors"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + // Attribute presence and value selectors + test_valid_selector('[att]'); + test_valid_selector('[att=val]', '[att="val"]'); + test_valid_selector('[att~=val]', '[att~="val"]'); + test_valid_selector('[att|=val]', '[att|="val"]'); + test_valid_selector('h1[title]'); + test_valid_selector("span[class='example']", 'span[class="example"]'); + test_valid_selector('a[hreflang=fr]', 'a[hreflang="fr"]'); + test_valid_selector("a[hreflang|='en']", 'a[hreflang|="en"]'); + + // Substring matching attribute selectors + test_valid_selector('[att^=val]', '[att^="val"]'); + test_valid_selector('[att$=val]', '[att$="val"]'); + test_valid_selector('[att*=val]', '[att*="val"]'); + test_valid_selector('object[type^="image/"]'); + test_valid_selector('a[href$=".html"]'); + test_valid_selector('p[title*="hello"]'); + + // From Attribute selectors and namespaces examples in spec: + test_valid_selector('[*|att]'); + test_valid_selector('[|att]', '[att]'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/child.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/child.html new file mode 100644 index 0000000..510c45db --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/child.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: Child combinators</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#child-combinators"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('body > p'); + test_valid_selector('div ol>li p', 'div ol > li p'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/class.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/class.html new file mode 100644 index 0000000..00abcf83 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/class.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: Class selectors</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#class-html"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('*.pastoral', + ['*.pastoral', '.pastoral']); + test_valid_selector('.pastoral', + ['*.pastoral', '.pastoral']); + test_valid_selector('h1.pastoral'); + test_valid_selector('p.pastoral.marine'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/descendant.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/descendant.html new file mode 100644 index 0000000..5ff3a7bb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/descendant.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: Descendant combinator</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#descendant-combinators"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('h1 em'); + test_valid_selector('div * p'); + test_valid_selector('div p *[href]', + ['div p *[href]', 'div p [href]']); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/id.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/id.html new file mode 100644 index 0000000..2441c42 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/id.html
@@ -0,0 +1,13 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: ID selectors</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#id-selectors"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('h1#chapter1'); + test_valid_selector('#chapter1'); + test_valid_selector('*#z98y', + ['*#z98y', '#z98y']); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/is.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/is.html new file mode 100644 index 0000000..6823644 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/is.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: The Matches-Any Pseudo-class: ':is()'</title> +<link rel="help" href="https://drafts.csswg.org/selectors/#matches"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector(':is(ul,ol,.list) > [hidden]', + ':is(ul, ol, .list) > [hidden]'); + test_valid_selector(':is(:hover,:focus)', + ':is(:hover, :focus)'); + test_valid_selector('a:is(:not(:hover))'); + + test_valid_selector(':is(#a)'); + test_valid_selector('.a.b ~ :is(.c.d ~ .e.f)'); + test_valid_selector('.a.b ~ .c.d:is(span.e + .f, .g.h > .i.j .k)'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/not.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/not.html new file mode 100644 index 0000000..3895683d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/not.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: The negation pseudo-class</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#negation"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('button:not([disabled])'); + test_valid_selector('*:not(foo)', + ['*:not(foo)', ':not(foo)']); + test_valid_selector(':not(:link):not(:visited)'); + test_valid_selector('*|*:not(*)', ':not(*)'); + test_valid_selector(':not(:hover)'); + test_valid_selector(':not(*|*)', ':not(*)'); + test_valid_selector('foo:not(bar)'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/sibling.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/sibling.html new file mode 100644 index 0000000..4f7a7a3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/sibling.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: Sibling combinators</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#sibling-combinators"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('math + p'); + test_valid_selector('h1.opener + h2'); + test_valid_selector('h1 ~ pre'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/universal.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/universal.html new file mode 100644 index 0000000..e944a93 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/universal.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: Universal selector</title> +<link rel="help" href="https://drafts.csswg.org/selectors-3/#universal-selector"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector('*'); + test_valid_selector('div :first-child', + ['div *:first-child', 'div :first-child']); + test_valid_selector('div *:first-child', + ['div *:first-child', 'div :first-child']); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/selectors/parsing/where.html b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/where.html new file mode 100644 index 0000000..3a90969 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/selectors/parsing/where.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Selectors: The Specificity-adjustment Pseudo-class: ':where()'</title> +<link rel="help" href="https://drafts.csswg.org/selectors/#zero-matches"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> + test_valid_selector(':where(ul,ol,.list) > [hidden]', + ':where(ul, ol, .list) > [hidden]'); + test_valid_selector(':where(:hover,:focus)', + ':where(:hover, :focus)'); + test_valid_selector('a:where(:not(:hover))'); + + test_valid_selector(':where(#a)'); + test_valid_selector('.a.b ~ :where(.c.d ~ .e.f)'); + test_valid_selector('.a.b ~ .c.d:where(span.e + .f, .g.h > .i.j .k)'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/custom-elements/form-associated/form-elements-namedItem.html b/third_party/blink/web_tests/external/wpt/custom-elements/form-associated/form-elements-namedItem.html new file mode 100644 index 0000000..385d0f2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/custom-elements/form-associated/form-elements-namedItem.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<script> +customElements.define('custom-input', class extends HTMLElement { + static get formAssociated() {return true;} +}); +</script> + +<form> + <custom-input id="custom-1" name="alone"></custom-input> + <custom-input id="custom-2" name="group"></custom-input> + <custom-input id="custom-3" name="group"></custom-input> +</form> + +<script> +test(() => { + const formElements = document.forms[0].elements; + assert_equals(formElements['invalid'],undefined); + assert_equals(formElements['alone'],document.getElementById('custom-1'),'Single input should be returned as-is'); + assert_true(formElements['group'] instanceof RadioNodeList,'Repeated names should result in RadioNodeList'); + const expected = [document.getElementById('custom-2'), + document.getElementById('custom-3')]; + assert_array_equals(formElements['group'],expected,'Repeated names should be contained in RadioNodeList, in tree order'); +}, 'Form associated custom elements should work with document.forms.elements.namedItem()'); + +</script> +</body> \ No newline at end of file
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/blocked-by-csp-ref.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/blocked-by-csp-ref.html new file mode 100644 index 0000000..f37d8a3e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/blocked-by-csp-ref.html
@@ -0,0 +1,5 @@ +<!doctype html> +<title>Test reference</title> +<style>img { border: solid; }</style> +It should say PASS below:<br> +<img alt="PASS">
diff --git a/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/blocked-by-csp.html b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/blocked-by-csp.html new file mode 100644 index 0000000..2416e5df --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/html/rendering/replaced-elements/images/blocked-by-csp.html
@@ -0,0 +1,8 @@ +<!doctype html> +<title>Images behave the same when blocked by CSP as when failing to load/broken</title> +<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1664156"> +<link rel="match" href="blocked-by-csp-ref.html"> +<meta http-equiv=content-security-policy content="img-src 'none'"> +<style>img { border: solid; }</style> +It should say PASS below:<br> +<img src=image alt="PASS">
diff --git a/third_party/blink/web_tests/external/wpt/mathml/support/box-comparison.js b/third_party/blink/web_tests/external/wpt/mathml/support/box-comparison.js index a574b01..b30ad279 100644 --- a/third_party/blink/web_tests/external/wpt/mathml/support/box-comparison.js +++ b/third_party/blink/web_tests/external/wpt/mathml/support/box-comparison.js
@@ -71,23 +71,24 @@ if (!FragmentHelper.isValidChildOfMrow(tag)) throw `Invalid argument: ${tag}`; + // FIXME <mrow> only needed as workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1658135 document.body.insertAdjacentHTML("beforeend", `<div style="position: absolute;">\ -<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\ -<div style="display: inline-block"><math>${MathMLFragments[tag]}</math></div>\ +<div style="display: inline-block"><math><mrow>${MathMLFragments[tag]}</mrow></math></div>\ +<div style="display: inline-block"><math><mrow>${MathMLFragments[tag]}</mrow></math></div>\ </div>`); var div = document.body.lastElementChild; var styleDiv = div.firstElementChild; - var styleMath = styleDiv.firstElementChild; - var styleElement = FragmentHelper.element(styleMath); + var styleParent = styleDiv.firstElementChild.firstElementChild; + var styleElement = FragmentHelper.element(styleParent); styleElement.setAttribute("style", style); - var styleMathBox = styleMath.getBoundingClientRect(); + var styleParentBox = styleParent.getBoundingClientRect(); var styleElementBox = styleElement.getBoundingClientRect(); var noStyleDiv = div.lastElementChild; - var noStyleMath = noStyleDiv.firstElementChild; - var noStyleElement = FragmentHelper.element(noStyleMath); - var noStyleMathBox = noStyleMath.getBoundingClientRect(); + var noStyleParent = noStyleDiv.firstElementChild.firstElementChild; + var noStyleElement = FragmentHelper.element(noStyleParent); + var noStyleParentBox = noStyleParent.getBoundingClientRect(); var noStyleElementBox = noStyleElement.getBoundingClientRect(); var preferredWidthDelta = @@ -98,8 +99,8 @@ return { preferred_width_delta: preferredWidthDelta, - width_delta: styleMathBox.width - noStyleMathBox.width, - height_delta: styleMathBox.height - noStyleMathBox.height, + width_delta: styleParentBox.width - noStyleParentBox.width, + height_delta: styleParentBox.height - noStyleParentBox.height, element_width_delta: styleElementBox.width - noStyleElementBox.width, element_height_delta: styleElementBox.height - noStyleElementBox.height };
diff --git a/third_party/blink/web_tests/external/wpt/webstorage/set.window.js b/third_party/blink/web_tests/external/wpt/webstorage/set.window.js index 1c20907..8e671d2d 100644 --- a/third_party/blink/web_tests/external/wpt/webstorage/set.window.js +++ b/third_party/blink/web_tests/external/wpt/webstorage/set.window.js
@@ -43,7 +43,7 @@ assert_equals(storage[key], proto); assert_equals(storage.getItem(key), null); assert_equals(storage[key] = value, value); - // Hidden because no [LegacyOverrideBuiltins]. + // Hidden because no [LegacyOverrideBuiltIns]. assert_equals(storage[key], proto); assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined); assert_equals(storage.getItem(key), value); @@ -62,7 +62,7 @@ storage.setItem(key, existing); - // Hidden because no [LegacyOverrideBuiltins]. + // Hidden because no [LegacyOverrideBuiltIns]. assert_equals(storage[key], proto); assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined); assert_equals(storage.getItem(key), existing); @@ -93,7 +93,7 @@ assert_equals(storage[key], proto); assert_equals(storage.getItem(key), null); assert_equals(storage[key] = value, value); - // Property is hidden because no [LegacyOverrideBuiltins]. + // Property is hidden because no [LegacyOverrideBuiltIns]. assert_equals(storage[key], proto); assert_equals(Object.getOwnPropertyDescriptor(storage, key), undefined); assert_equals(storage.getItem(key), value);
diff --git a/third_party/blink/web_tests/fast/css/css-selector-text-expected.txt b/third_party/blink/web_tests/fast/css/css-selector-text-expected.txt index 82bc45b..c20a7e9f 100644 --- a/third_party/blink/web_tests/fast/css/css-selector-text-expected.txt +++ b/third_party/blink/web_tests/fast/css/css-selector-text-expected.txt
@@ -54,7 +54,7 @@ PASS parseThenSerializeRule(':lang(a) { }') is ':lang(a) { }' PASS parseThenSerializeRule(':not(a) { }') is ':not(a) { }' -PASS parseThenSerializeRule(':-webkit-any(a,b,p) { }') is ':-webkit-any(a,b,p) { }' +PASS parseThenSerializeRule(':-webkit-any(a, b, p) { }') is ':-webkit-any(a, b, p) { }' PASS parseThenSerializeRule('::after { }') is '::after { }' @@ -98,8 +98,8 @@ PASS parseThenSerializeRule('input:not([type="file"]):focus-within { }') is 'input:not([type="file"]):focus-within { }' PASS parseThenSerializeRule(':-webkit-any([type="file"]) { }') is ':-webkit-any([type="file"]) { }' PASS parseThenSerializeRule(':-webkit-any(:hover) { }') is ':-webkit-any(:hover) { }' -PASS parseThenSerializeRule('input:-webkit-any([type="file"],:hover,:focus):enabled { }') is 'input:-webkit-any([type="file"],:hover,:focus):enabled { }' -PASS parseThenSerializeRule(':-webkit-any(input[type="file"],a:hover,button:focus) { }') is ':-webkit-any(input[type="file"],a:hover,button:focus) { }' +PASS parseThenSerializeRule('input:-webkit-any([type="file"], :hover, :focus):enabled { }') is 'input:-webkit-any([type="file"], :hover, :focus):enabled { }' +PASS parseThenSerializeRule(':-webkit-any(input[type="file"], a:hover, button:focus) { }') is ':-webkit-any(input[type="file"], a:hover, button:focus) { }' PASS parseThenSerializeRule(':-webkit-any(.class1.class2.class3) { }') is ':-webkit-any(.class1.class2.class3) { }' PASS parseThenSerializeRule(':-webkit-any(.class1:hover) { }') is ':-webkit-any(.class1:hover) { }' PASS parseThenSerializeRule(':-webkit-any(a.class1.class2.class3:hover) { }') is ':-webkit-any(a.class1.class2.class3:hover) { }' @@ -122,7 +122,7 @@ PASS parseThenSerializeRule(':before { }') is '::before { }' PASS parseThenSerializeRule(':first-letter { }') is '::first-letter { }' PASS parseThenSerializeRule(':first-line { }') is '::first-line { }' -PASS parseThenSerializeRule(':-webkit-any( a.class1 , #id,[attr] ) { }') is ':-webkit-any(a.class1,#id,[attr]) { }' +PASS parseThenSerializeRule(':-webkit-any( a.class1 , #id,[attr] ) { }') is ':-webkit-any(a.class1, #id, [attr]) { }' PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/css/css-selector-text.html b/third_party/blink/web_tests/fast/css/css-selector-text.html index 9c0998ce..166e418 100644 --- a/third_party/blink/web_tests/fast/css/css-selector-text.html +++ b/third_party/blink/web_tests/fast/css/css-selector-text.html
@@ -85,7 +85,7 @@ testSelectorRoundTrip(":lang(a)"); testSelectorRoundTrip(":not(a)"); -testSelectorRoundTrip(":-webkit-any(a,b,p)"); +testSelectorRoundTrip(":-webkit-any(a, b, p)"); debug(''); @@ -135,8 +135,8 @@ testSelectorRoundTrip('input:not([type="file"]):focus-within'); testSelectorRoundTrip(':-webkit-any([type="file"])'); testSelectorRoundTrip(':-webkit-any(:hover)'); -testSelectorRoundTrip('input:-webkit-any([type="file"],:hover,:focus):enabled'); -testSelectorRoundTrip(':-webkit-any(input[type="file"],a:hover,button:focus)'); +testSelectorRoundTrip('input:-webkit-any([type="file"], :hover, :focus):enabled'); +testSelectorRoundTrip(':-webkit-any(input[type="file"], a:hover, button:focus)'); testSelectorRoundTrip(':-webkit-any(.class1.class2.class3)'); testSelectorRoundTrip(':-webkit-any(.class1:hover)'); testSelectorRoundTrip(':-webkit-any(a.class1.class2.class3:hover)'); @@ -163,7 +163,7 @@ shouldBe("parseThenSerializeRule(':before { }')", "'::before { }'"); shouldBe("parseThenSerializeRule(':first-letter { }')", "'::first-letter { }'"); shouldBe("parseThenSerializeRule(':first-line { }')", "'::first-line { }'"); -shouldBe("parseThenSerializeRule(':-webkit-any( a.class1 , #id,[attr] ) { }')","':-webkit-any(a.class1,#id,[attr]) { }'"); +shouldBe("parseThenSerializeRule(':-webkit-any( a.class1 , #id,[attr] ) { }')","':-webkit-any(a.class1, #id, [attr]) { }'"); debug('');
diff --git a/third_party/blink/web_tests/fast/css/css-set-selector-text-expected.txt b/third_party/blink/web_tests/fast/css/css-set-selector-text-expected.txt index d032a2f..908a3f6 100644 --- a/third_party/blink/web_tests/fast/css/css-set-selector-text-expected.txt +++ b/third_party/blink/web_tests/fast/css/css-set-selector-text-expected.txt
@@ -66,7 +66,7 @@ PASS setThenReadSelectorText(':lang(a)') is ':lang(a)' PASS setThenReadSelectorText(':not(a)') is ':not(a)' -PASS setThenReadSelectorText(':-webkit-any(a,b,p)') is ':-webkit-any(a,b,p)' +PASS setThenReadSelectorText(':-webkit-any(a, b, p)') is ':-webkit-any(a, b, p)' PASS setThenReadSelectorText('::after') is '::after' @@ -110,8 +110,8 @@ PASS setThenReadSelectorText('input:not([type="file"]):focus-within') is 'input:not([type="file"]):focus-within' PASS setThenReadSelectorText(':-webkit-any([type="file"])') is ':-webkit-any([type="file"])' PASS setThenReadSelectorText(':-webkit-any(:hover)') is ':-webkit-any(:hover)' -PASS setThenReadSelectorText('input:-webkit-any([type="file"],:hover,:focus):enabled') is 'input:-webkit-any([type="file"],:hover,:focus):enabled' -PASS setThenReadSelectorText(':-webkit-any(input[type="file"],a:hover,button:focus)') is ':-webkit-any(input[type="file"],a:hover,button:focus)' +PASS setThenReadSelectorText('input:-webkit-any([type="file"], :hover, :focus):enabled') is 'input:-webkit-any([type="file"], :hover, :focus):enabled' +PASS setThenReadSelectorText(':-webkit-any(input[type="file"], a:hover, button:focus)') is ':-webkit-any(input[type="file"], a:hover, button:focus)' PASS setThenReadSelectorText(':-webkit-any(.class1.class2.class3)') is ':-webkit-any(.class1.class2.class3)' PASS setThenReadSelectorText(':-webkit-any(.class1:hover)') is ':-webkit-any(.class1:hover)' PASS setThenReadSelectorText(':-webkit-any(a.class1.class2.class3:hover)') is ':-webkit-any(a.class1.class2.class3:hover)' @@ -134,7 +134,7 @@ PASS setThenReadSelectorText(':before') is '::before' PASS setThenReadSelectorText(':first-letter') is '::first-letter' PASS setThenReadSelectorText(':first-line') is '::first-line' -PASS setThenReadSelectorText(':-webkit-any( a.class1 , #id,[attr] )') is ':-webkit-any(a.class1,#id,[attr])' +PASS setThenReadSelectorText(':-webkit-any( a.class1 , #id,[attr] )') is ':-webkit-any(a.class1, #id, [attr])' PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/css/css-set-selector-text.html b/third_party/blink/web_tests/fast/css/css-set-selector-text.html index f3d5e41..99c643c 100644 --- a/third_party/blink/web_tests/fast/css/css-set-selector-text.html +++ b/third_party/blink/web_tests/fast/css/css-set-selector-text.html
@@ -102,7 +102,7 @@ testSelectorRoundTrip(":lang(a)"); testSelectorRoundTrip(":not(a)"); -testSelectorRoundTrip(":-webkit-any(a,b,p)"); +testSelectorRoundTrip(":-webkit-any(a, b, p)"); debug(''); @@ -152,8 +152,8 @@ testSelectorRoundTrip('input:not([type="file"]):focus-within'); testSelectorRoundTrip(':-webkit-any([type="file"])'); testSelectorRoundTrip(':-webkit-any(:hover)'); -testSelectorRoundTrip('input:-webkit-any([type="file"],:hover,:focus):enabled'); -testSelectorRoundTrip(':-webkit-any(input[type="file"],a:hover,button:focus)'); +testSelectorRoundTrip('input:-webkit-any([type="file"], :hover, :focus):enabled'); +testSelectorRoundTrip(':-webkit-any(input[type="file"], a:hover, button:focus)'); testSelectorRoundTrip(':-webkit-any(.class1.class2.class3)'); testSelectorRoundTrip(':-webkit-any(.class1:hover)'); testSelectorRoundTrip(':-webkit-any(a.class1.class2.class3:hover)'); @@ -180,7 +180,7 @@ shouldBe("setThenReadSelectorText(':before')", "'::before'"); shouldBe("setThenReadSelectorText(':first-letter')", "'::first-letter'"); shouldBe("setThenReadSelectorText(':first-line')", "'::first-line'"); -shouldBe("setThenReadSelectorText(':-webkit-any( a.class1 , #id,[attr] )')","':-webkit-any(a.class1,#id,[attr])'"); +shouldBe("setThenReadSelectorText(':-webkit-any( a.class1 , #id,[attr] )')","':-webkit-any(a.class1, #id, [attr])'"); debug('');
diff --git a/third_party/blink/web_tests/fast/css/cue-serialize-expected.txt b/third_party/blink/web_tests/fast/css/cue-serialize-expected.txt index e3ceae0..1f3b9420 100644 --- a/third_party/blink/web_tests/fast/css/cue-serialize-expected.txt +++ b/third_party/blink/web_tests/fast/css/cue-serialize-expected.txt
@@ -5,7 +5,7 @@ PASS rules.length is 3 PASS rules[0].selectorText is '::cue' PASS rules[1].selectorText is '::cue(c)' -PASS rules[2].selectorText is '::cue(c,.class,#id:past,i:future)' +PASS rules[2].selectorText is '::cue(c, .class, #id:past, i:future)' PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/blink/web_tests/fast/css/cue-serialize.html b/third_party/blink/web_tests/fast/css/cue-serialize.html index a93e83f..b1fe246 100644 --- a/third_party/blink/web_tests/fast/css/cue-serialize.html +++ b/third_party/blink/web_tests/fast/css/cue-serialize.html
@@ -13,5 +13,5 @@ shouldBe("rules.length", "3"); shouldBe("rules[0].selectorText", "'::cue'"); shouldBe("rules[1].selectorText", "'::cue(c)'"); -shouldBe("rules[2].selectorText", "'::cue(c,.class,#id:past,i:future)'"); +shouldBe("rules[2].selectorText", "'::cue(c, .class, #id:past, i:future)'"); </script>
diff --git a/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text-expected.txt b/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text-expected.txt index 6a6031d..2d981d8 100644 --- a/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text-expected.txt +++ b/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text-expected.txt
@@ -2,7 +2,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS document.getElementById('style1').sheet.cssRules.item(0).cssText is ".foo:host-context(div,body.mytheme,p#myid,.bar:first-child,span:hover) > div { display: block; }" +PASS document.getElementById('style1').sheet.cssRules.item(0).cssText is ".foo:host-context(div, body.mytheme, p#myid, .bar:first-child, span:hover) > div { display: block; }" PASS document.getElementById('style1').sheet.cssRules.item(1).cssText is ":host-context(*) { display: block; }" PASS document.getElementById('style-invalid').sheet.cssRules.length is 0 PASS successfullyParsed is true
diff --git a/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text.html b/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text.html index 2cae1d0d..3102020 100644 --- a/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text.html +++ b/third_party/blink/web_tests/fast/dom/shadow/host-context-pseudo-class-css-text.html
@@ -17,7 +17,7 @@ </head> <script> description("Test for cssText of ':host-context()' rule."); -shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(0).cssText", ".foo:host-context(div,body.mytheme,p#myid,.bar:first-child,span:hover) > div { display: block; }"); +shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(0).cssText", ".foo:host-context(div, body.mytheme, p#myid, .bar:first-child, span:hover) > div { display: block; }"); shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(1).cssText", ":host-context(*) { display: block; }"); shouldBe("document.getElementById('style-invalid').sheet.cssRules.length", "0"); </script>
diff --git a/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text-expected.txt b/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text-expected.txt index 6cea463a..f5e2db2 100644 --- a/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text-expected.txt +++ b/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text-expected.txt
@@ -2,7 +2,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". -PASS document.getElementById('style1').sheet.cssRules.item(0).cssText is ".foo:host(div,body.mytheme,p#myid,.bar:first-child,span:hover) > div { display: block; }" +PASS document.getElementById('style1').sheet.cssRules.item(0).cssText is ".foo:host(div, body.mytheme, p#myid, .bar:first-child, span:hover) > div { display: block; }" PASS document.getElementById('style1').sheet.cssRules.item(1).cssText is ":host { display: block; }" PASS document.getElementById('style1').sheet.cssRules.item(2).cssText is ":host(*) { display: block; }" PASS document.getElementById('style-invalid').sheet.cssRules.length is 0
diff --git a/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text.html b/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text.html index ee11a5d..ab23214 100644 --- a/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text.html +++ b/third_party/blink/web_tests/fast/dom/shadow/host-pseudo-class-css-text.html
@@ -18,7 +18,7 @@ </head> <script> description("Test for cssText of ':host()' rule."); -shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(0).cssText", ".foo:host(div,body.mytheme,p#myid,.bar:first-child,span:hover) > div { display: block; }"); +shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(0).cssText", ".foo:host(div, body.mytheme, p#myid, .bar:first-child, span:hover) > div { display: block; }"); shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(1).cssText", ":host { display: block; }"); shouldBeEqualToString("document.getElementById('style1').sheet.cssRules.item(2).cssText", ":host(*) { display: block; }"); shouldBe("document.getElementById('style-invalid').sheet.cssRules.length", "0");
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-encoding-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-encoding-expected.txt new file mode 100644 index 0000000..31e821e --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-encoding-expected.txt
@@ -0,0 +1,5 @@ +Test to make sure header values are correctly encoded as UTF8. +Network Enabled +before-æøå-after +before-ß-after +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-encoding.js b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-encoding.js new file mode 100644 index 0000000..fdc3c6f --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/network/request-will-be-sent-encoding.js
@@ -0,0 +1,25 @@ +(async function(testRunner) { + const {page, session, dp} = await testRunner.startBlank( + `Test to make sure header values are correctly encoded as UTF8.`); + + await dp.Network.enable(); + testRunner.log('Network Enabled'); + + dp.Network.onRequestWillBeSentExtraInfo(event => { + testRunner.log(event.params.headers['Accept']); + testRunner.log(event.params.headers['X-Test']); + testRunner.completeTest(); + }); + + await session.evaluate(` + fetch('index.html', { + method: 'get', + headers: { + 'Accept': 'before-æøå-after', + 'X-Test': 'before-ß-after', + } + }) + .then(result => result.text()) + .then(console.log); + `); +})
diff --git a/third_party/blink/web_tests/virtual/out-of-blink-cspee/README.md b/third_party/blink/web_tests/virtual/out-of-blink-cspee/README.md index 1df02495f..0ef9577 100644 --- a/third_party/blink/web_tests/virtual/out-of-blink-cspee/README.md +++ b/third_party/blink/web_tests/virtual/out-of-blink-cspee/README.md
@@ -1,4 +1,6 @@ This directory is for testing out-of-blink CSP Embedded Enforcement. -This test suite runs the tests with --enable-features=OutOfBlinkCSPEE. +The feature has been now turned on by default, so we keep this virtual test +suite for the previous, in-blink functionality. +This test suite runs the tests with --disable-features=OutOfBlinkCSPEE.
diff --git a/third_party/closure_compiler/externs/file_manager_private.js b/third_party/closure_compiler/externs/file_manager_private.js index 6d5ec20..cb2f03e 100644 --- a/third_party/closure_compiler/externs/file_manager_private.js +++ b/third_party/closure_compiler/externs/file_manager_private.js
@@ -477,7 +477,8 @@ * @typedef {{ * type: !chrome.fileManagerPrivate.DriveConnectionStateType, * reason: (!chrome.fileManagerPrivate.DriveOfflineReason|undefined), - * hasCellularNetworkAccess: boolean + * hasCellularNetworkAccess: boolean, + * canPinHostedFiles: boolean * }} */ chrome.fileManagerPrivate.DriveConnectionState;
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index ef55aa8..fb48d46 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -41299,6 +41299,8 @@ <int value="-1332267458" label="RemoveNavigationHistory:enabled"/> <int value="-1331831950" label="site-isolation-for-password-sites:enabled"/> <int value="-1330409814" label="ContextMenuCopyImage:enabled"/> + <int value="-1329586063" + label="MigrateDefaultChromeAppToWebAppsNonGSuite:disabled"/> <int value="-1327676774" label="disable-accelerated-mjpeg-decode"/> <int value="-1326671705" label="TrustTokens:enabled"/> <int value="-1326463296" label="SSLCommittedInterstitials:disabled"/> @@ -44285,6 +44287,8 @@ <int value="1810258949" label="DisplayLocking:enabled"/> <int value="1810311887" label="WebAssemblyThreads:enabled"/> <int value="1812368073" label="enable-new-app-list-mixer"/> + <int value="1813370929" + label="MigrateDefaultChromeAppToWebAppsNonGSuite:enabled"/> <int value="1814671708" label="disable-password-manager-reauthentication"/> <int value="1816174635" label="RequestUnbufferedDispatch:enabled"/> <int value="1816723085" label="SchemefulSameSite:enabled"/> @@ -44568,6 +44572,8 @@ <int value="2085438501" label="ChromeHome:enabled"/> <int value="2089897928" label="enable-audio-focus"/> <int value="2091002949" label="RemoveNavigationHistory:disabled"/> + <int value="2091943748" + label="MigrateDefaultChromeAppToWebAppsGSuite:disabled"/> <int value="2092605092" label="ChromeHomeShowGoogleGWhenUrlCleared:disabled"/> <int value="2092968851" label="SharingSendViaSync:enabled"/> <int value="2093235103" label="default-tile-width"/> @@ -44612,6 +44618,8 @@ <int value="2137599770" label="enable-win32k-renderer-lockdown"/> <int value="2138146331" label="OmniboxVoiceSearchAlwaysVisible:enabled"/> <int value="2139048614" label="UseSurfaceLayerForVideo:enabled"/> + <int value="2140453427" + label="MigrateDefaultChromeAppToWebAppsGSuite:enabled"/> <int value="2141067485" label="SystemWebApps:enabled"/> <int value="2141463681" label="enable-offer-upload-credit-cards"/> <int value="2142661816" label="AllowRemoteContextForNotifications:disabled"/> @@ -50901,6 +50909,9 @@ </enum> <enum name="NewTabPage.ExploreOffline.Action"> + <obsolete> + Deprecated as of 08/2020. + </obsolete> <int value="0" label="Displayed explore offline card on NTP"/> <int value="1" label="Clicked confirm button"/> <int value="2" label="Clicked cancel button"/> @@ -53434,6 +53445,7 @@ <int value="1203" label="Input Method Options"/> <int value="1204" label="Languages"/> <int value="1205" label="Input"/> + <int value="1206" label="Customize spell check"/> <int value="1300" label="Network File Shares"/> <int value="1400" label="Printing Details"/> <int value="1500" label="Manage Accessibility"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index e1f1a7e3..305e198 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -112371,6 +112371,9 @@ <histogram name="NewTabPage.ExploreOffline.Action" enum="NewTabPage.ExploreOffline.Action" expires_after="2020-08-01"> + <obsolete> + Deprecated as of 08/2020. + </obsolete> <owner>shaktisahu@chromium.org</owner> <owner>clank-downloads@google.com</owner> <summary>
diff --git a/ui/file_manager/base/js/filtered_volume_manager.js b/ui/file_manager/base/js/filtered_volume_manager.js index 0c5bfbe2..0f7ffb05 100644 --- a/ui/file_manager/base/js/filtered_volume_manager.js +++ b/ui/file_manager/base/js/filtered_volume_manager.js
@@ -292,6 +292,7 @@ type: chrome.fileManagerPrivate.DriveConnectionStateType.OFFLINE, reason: chrome.fileManagerPrivate.DriveOfflineReason.NO_SERVICE, hasCellularNetworkAccess: false, + canPinHostedFiles: false, }; }
diff --git a/ui/file_manager/file_manager/background/js/mock_volume_manager.js b/ui/file_manager/file_manager/background/js/mock_volume_manager.js index 82c8ed3..87da263 100644 --- a/ui/file_manager/file_manager/background/js/mock_volume_manager.js +++ b/ui/file_manager/file_manager/background/js/mock_volume_manager.js
@@ -17,6 +17,7 @@ type: /** @type {!chrome.fileManagerPrivate.DriveConnectionStateType} */ ( 'ONLINE'), hasCellularNetworkAccess: false, + canPinHostedFiles: false, }; // Create Drive. Drive attempts to resolve FilesSystemURLs for '/root',
diff --git a/ui/file_manager/file_manager/background/js/volume_manager_impl.js b/ui/file_manager/file_manager/background/js/volume_manager_impl.js index 23bfc60..8f0355c 100644 --- a/ui/file_manager/file_manager/background/js/volume_manager_impl.js +++ b/ui/file_manager/file_manager/background/js/volume_manager_impl.js
@@ -38,7 +38,8 @@ this.driveConnectionState_ = { type: chrome.fileManagerPrivate.DriveConnectionStateType.OFFLINE, reason: chrome.fileManagerPrivate.DriveOfflineReason.NO_SERVICE, - hasCellularNetworkAccess: false + hasCellularNetworkAccess: false, + canPinHostedFiles: false, }; chrome.fileManagerPrivate.onDriveConnectionStatusChanged.addListener(
diff --git a/ui/file_manager/file_manager/common/js/util.js b/ui/file_manager/file_manager/common/js/util.js index 2459e60..d85d81e 100644 --- a/ui/file_manager/file_manager/common/js/util.js +++ b/ui/file_manager/file_manager/common/js/util.js
@@ -1468,15 +1468,6 @@ }; /** - * Returns true if Drive bidirectional native messaging is enabled. - * @return {boolean} - */ -util.isDriveBidirectionalNativeMessagingEnabled = () => { - return loadTimeData.getBoolean( - 'DRIVE_BIDIRECTIONAL_NATIVE_MESSAGING_ENABLED'); -}; - -/** * Retrieves all entries inside the given |rootEntry|. * @param {!DirectoryEntry} rootEntry * @param {function(!Array<!Entry>)} entriesCallback Called when some chunk of
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model.js b/ui/file_manager/file_manager/foreground/js/actions_model.js index 14b71014..89a95d9 100644 --- a/ui/file_manager/file_manager/foreground/js/actions_model.js +++ b/ui/file_manager/file_manager/foreground/js/actions_model.js
@@ -137,10 +137,13 @@ * @param {!MetadataModel} metadataModel * @param {!DriveSyncHandler} driveSyncHandler * @param {!ActionModelUI} ui + * @param {!VolumeManager} volumeManager * @param {boolean} value * @param {function()} onExecute */ - constructor(entries, metadataModel, driveSyncHandler, ui, value, onExecute) { + constructor( + entries, metadataModel, driveSyncHandler, ui, volumeManager, value, + onExecute) { /** * @private {!Array<!Entry>} * @const @@ -160,6 +163,12 @@ this.driveSyncHandler_ = driveSyncHandler; /** + * @private {!VolumeManager} + * @const + */ + this.volumeManager_ = volumeManager; + + /** * @private {!ActionModelUI} * @const */ @@ -176,6 +185,13 @@ * @const */ this.onExecute_ = onExecute; + + /** + * @private {boolean} + * @const + */ + this.containsOnlyHosted_ = metadataModel.getCache(entries, ['hosted']) + .every(metadata => metadata.hosted); } /** @@ -183,31 +199,25 @@ * @param {!MetadataModel} metadataModel * @param {!DriveSyncHandler} driveSyncHandler * @param {!ActionModelUI} ui + * @param {!VolumeManager} volumeManager * @param {boolean} value * @param {function()} onExecute * @return {DriveToggleOfflineAction} */ static create( - entries, metadataModel, driveSyncHandler, ui, value, onExecute) { - const actionableEntries = entries.filter(entry => { - const metadata = metadataModel.getCache([entry], ['hosted', 'pinned'])[0]; - if (!util.isDriveBidirectionalNativeMessagingEnabled() && - metadata.hosted) { - return false; - } - if (metadata.pinned === value) { - return false; - } - return true; - }); + entries, metadataModel, driveSyncHandler, ui, volumeManager, value, + onExecute) { + const actionableEntries = entries.filter( + entry => + metadataModel.getCache([entry], ['pinned'])[0].pinned !== value); if (actionableEntries.length === 0) { return null; } return new DriveToggleOfflineAction( - actionableEntries, metadataModel, driveSyncHandler, ui, value, - onExecute); + actionableEntries, metadataModel, driveSyncHandler, ui, volumeManager, + value, onExecute); } /** @@ -230,8 +240,15 @@ return; } currentEntry = entries.shift(); - chrome.fileManagerPrivate.pinDriveFile( - currentEntry, this.value_, steps.entryPinned); + // Skip hosted files if we cannot pin them. + if (this.volumeManager_.getDriveConnectionState().canPinHostedFiles || + !this.metadataModel_.getCache([currentEntry], ['hosted'])[0] + .hosted) { + chrome.fileManagerPrivate.pinDriveFile( + currentEntry, this.value_, steps.entryPinned); + } else { + steps.start(); + } }, // Check the result of pinning. @@ -283,7 +300,8 @@ * @override */ canExecute() { - return true; + return this.volumeManager_.getDriveConnectionState().canPinHostedFiles || + !this.containsOnlyHosted_; } /** @@ -733,7 +751,8 @@ const saveForOfflineAction = DriveToggleOfflineAction.create( this.entries_, this.metadataModel_, this.driveSyncHandler_, - this.ui_, true, this.invalidate_.bind(this)); + this.ui_, this.volumeManager_, true, + this.invalidate_.bind(this)); if (saveForOfflineAction) { actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE] = saveForOfflineAction; @@ -741,7 +760,8 @@ const offlineNotNecessaryAction = DriveToggleOfflineAction.create( this.entries_, this.metadataModel_, this.driveSyncHandler_, - this.ui_, false, this.invalidate_.bind(this)); + this.ui_, this.volumeManager_, false, + this.invalidate_.bind(this)); if (offlineNotNecessaryAction) { actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY] = offlineNotNecessaryAction;
diff --git a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js index 3d31576..ece9076 100644 --- a/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/actions_model_unittest.js
@@ -159,6 +159,7 @@ volumeManager.driveConnectionState = { type: chrome.fileManagerPrivate.DriveConnectionStateType.OFFLINE, hasCellularNetworkAccess: false, + canPinHostedFiles: false, }; assertFalse(shareAction.canExecute()); @@ -311,6 +312,220 @@ } /** + * Tests that the correct actions are available for a Google Drive hosted file. + */ +function testDriveHostedFileEntry(callback) { + const testDocument = MockFileEntry.create(driveFileSystem, '/test.gdoc'); + const testFile = MockFileEntry.create(driveFileSystem, '/test.txt'); + driveFileSystem.entries['/test.gdoc'] = testDocument; + driveFileSystem.entries['/test.txt'] = testFile; + + const metadataModel = new MockMetadataModel({}); + metadataModel.set(testDocument, {hosted: true, pinned: false}); + metadataModel.set(testFile, {hosted: false, pinned: false}); + volumeManager.driveConnectionState = { + type: chrome.fileManagerPrivate.DriveConnectionStateType.ONLINE, + hasCellularNetworkAccess: false, + canPinHostedFiles: true, + }; + chrome.fileManagerPrivate.pinDriveFile = (entry, pin, callback) => { + const metadata = metadataModel.getCache([entry])[0]; + metadata.pinned = pin; + metadataModel.set(entry, metadata); + callback(); + }; + + let model = new ActionsModel( + volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui, + [testDocument]); + + return reportPromise( + model.initialize() + .then(() => { + const actions = model.getActions(); + + // 'Save for Offline' should be enabled. + const saveForOfflineAction = + actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE]; + assertTrue(!!saveForOfflineAction); + assertTrue(saveForOfflineAction.canExecute()); + + // Check the actions for multiple selection. + model = new ActionsModel( + volumeManager, metadataModel, shortcutsModel, driveSyncHandler, + ui, [testDocument, testFile]); + return model.initialize(); + }) + .then(() => { + const actions = model.getActions(); + + // 'Offline not Necessary' should not be enabled. + assertFalse(actions.hasOwnProperty( + ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY)); + + // 'Save for Offline' should be enabled. + const saveForOfflineAction = + actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE]; + assertTrue(!!saveForOfflineAction); + assertTrue(saveForOfflineAction.canExecute()); + + // For pinning, invalidating is done asynchronously, so we need to + // wait for it with a promise. + return new Promise((fulfill, reject) => { + model.addEventListener('invalidated', () => { + fulfill(); + }); + saveForOfflineAction.execute(); + }); + }) + .then(() => { + assertTrue(!!metadataModel.getCache([testDocument])[0].pinned); + assertTrue(!!metadataModel.getCache([testFile])[0].pinned); + + model = new ActionsModel( + volumeManager, metadataModel, shortcutsModel, driveSyncHandler, + ui, [testDocument, testFile]); + return model.initialize(); + }) + .then(() => { + const actions = model.getActions(); + + // 'Offline not Necessary' should be enabled. + const offlineNotNecessaryAction = + actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY]; + assertTrue(!!offlineNotNecessaryAction); + assertTrue(offlineNotNecessaryAction.canExecute()); + + // 'Save for Offline' should not be enabled. + assertFalse(actions.hasOwnProperty( + ActionsModel.CommonActionId.SAVE_FOR_OFFLINE)); + + // For pinning, invalidating is done asynchronously, so we need to + // wait for it with a promise. + return new Promise((fulfill, reject) => { + model.addEventListener('invalidated', () => { + fulfill(); + }); + offlineNotNecessaryAction.execute(); + }); + }) + .then(() => { + assertFalse(!!metadataModel.getCache([testDocument])[0].pinned); + assertFalse(!!metadataModel.getCache([testFile])[0].pinned); + }), + callback); +} + +/** + * Tests that the correct actions are available for a Google Drive hosted file + * when the user does not have the required extension installed. + */ +function testDriveHostedFileEntryWithoutExtension(callback) { + const testDocument = MockFileEntry.create(driveFileSystem, '/test.gdoc'); + const testFile = MockFileEntry.create(driveFileSystem, '/test.txt'); + driveFileSystem.entries['/test.gdoc'] = testDocument; + driveFileSystem.entries['/test.txt'] = testFile; + + const metadataModel = new MockMetadataModel({}); + metadataModel.set(testDocument, {hosted: true, pinned: false}); + metadataModel.set(testFile, {hosted: false, pinned: false}); + volumeManager.driveConnectionState = { + type: chrome.fileManagerPrivate.DriveConnectionStateType.ONLINE, + hasCellularNetworkAccess: false, + canPinHostedFiles: false, + }; + chrome.fileManagerPrivate.pinDriveFile = (entry, pin, callback) => { + const metadata = metadataModel.getCache([entry])[0]; + metadata.pinned = pin; + metadataModel.set(entry, metadata); + callback(); + }; + + let model = new ActionsModel( + volumeManager, metadataModel, shortcutsModel, driveSyncHandler, ui, + [testDocument]); + + return reportPromise( + model.initialize() + .then(() => { + const actions = model.getActions(); + + // 'Save for Offline' should be enabled, but not executable. + const saveForOfflineAction = + actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE]; + assertTrue(!!saveForOfflineAction); + assertFalse(saveForOfflineAction.canExecute()); + + // Check the actions for multiple selection. + model = new ActionsModel( + volumeManager, metadataModel, shortcutsModel, driveSyncHandler, + ui, [testDocument, testFile]); + return model.initialize(); + }) + .then(() => { + const actions = model.getActions(); + + // 'Offline not Necessary' should not be enabled. + assertFalse(actions.hasOwnProperty( + ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY)); + + // 'Save for Offline' should be enabled even though we can't pin + // hosted files as we've also selected a non-hosted file. + const saveForOfflineAction = + actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE]; + assertTrue(!!saveForOfflineAction); + assertTrue(saveForOfflineAction.canExecute()); + + // For pinning, invalidating is done asynchronously, so we need to + // wait for it with a promise. + return new Promise((fulfill, reject) => { + model.addEventListener('invalidated', () => { + fulfill(); + }); + saveForOfflineAction.execute(); + }); + }) + .then(() => { + assertFalse(!!metadataModel.getCache([testDocument])[0].pinned); + assertTrue(!!metadataModel.getCache([testFile])[0].pinned); + + model = new ActionsModel( + volumeManager, metadataModel, shortcutsModel, driveSyncHandler, + ui, [testDocument, testFile]); + return model.initialize(); + }) + .then(() => { + const actions = model.getActions(); + + // 'Offline not Necessary' should be enabled. + const offlineNotNecessaryAction = + actions[ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY]; + assertTrue(!!offlineNotNecessaryAction); + assertTrue(offlineNotNecessaryAction.canExecute()); + + // 'Save for Offline' should be enabled, but not executable. + const saveForOfflineAction = + actions[ActionsModel.CommonActionId.SAVE_FOR_OFFLINE]; + assertTrue(!!saveForOfflineAction); + assertFalse(saveForOfflineAction.canExecute()); + + // For pinning, invalidating is done asynchronously, so we need to + // wait for it with a promise. + return new Promise((fulfill, reject) => { + model.addEventListener('invalidated', () => { + fulfill(); + }); + offlineNotNecessaryAction.execute(); + }); + }) + .then(() => { + assertFalse(!!metadataModel.getCache([testDocument])[0].pinned); + assertFalse(!!metadataModel.getCache([testFile])[0].pinned); + }), + callback); +} + +/** * Tests that a Team Drive Root entry has the correct actions available. */ function testTeamDriveRootEntry(callback) { @@ -486,6 +701,7 @@ volumeManager.driveConnectionState = { type: chrome.fileManagerPrivate.DriveConnectionStateType.OFFLINE, hasCellularNetworkAccess: false, + canPinHostedFiles: false, }; assertTrue(shareAction.canExecute()); assertEquals('Share it!', shareAction.getTitle());
diff --git a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js index 944d2d5..78f4700 100644 --- a/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js +++ b/ui/file_manager/file_manager/foreground/js/fake_file_selection_handler.js
@@ -31,4 +31,8 @@ addEventListener(...args) { return this.eventTarget_.addEventListener(...args); } + + isAvailable() { + return true; + } }
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js index c819499..1724d6bf 100644 --- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js +++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1816,7 +1816,10 @@ const offlineNotNeededAction = actionsModel.getAction( ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY); // Saving for offline has a priority if both actions are available. - const action = saveForOfflineAction || offlineNotNeededAction; + let action = offlineNotNeededAction; + if (saveForOfflineAction && saveForOfflineAction.canExecute()) { + action = saveForOfflineAction; + } if (action) { actionsController.executeAction(action); } @@ -1845,8 +1848,12 @@ actionsModel.getAction(ActionsModel.CommonActionId.SAVE_FOR_OFFLINE); const offlineNotNeededAction = actionsModel.getAction( ActionsModel.CommonActionId.OFFLINE_NOT_NECESSARY); - const action = saveForOfflineAction || offlineNotNeededAction; - command.checked = !!offlineNotNeededAction && !saveForOfflineAction; + let action = offlineNotNeededAction; + command.checked = !!offlineNotNeededAction; + if (saveForOfflineAction && saveForOfflineAction.canExecute()) { + action = saveForOfflineAction; + command.checked = false; + } event.canExecute = action && action.canExecute(); command.disabled = !event.canExecute; }
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js index e549671..6aff5d4 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller.js
@@ -1232,7 +1232,8 @@ } /** - * @return {boolean} Returns true if the current directory is not read only. + * @return {boolean} Returns true if the current directory is not read only, + * or any of the selected entries isn't read-only. * @public */ canCutOrDrag() { @@ -1247,6 +1248,13 @@ if (metadata.some(item => item.canDelete === false)) { return false; } + + for (let i = 0; i < entries.length; i++) { + if (util.isNonModifiable(this.volumeManager_, entries[i])) { + return false; + } + } + return true; }
diff --git a/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js b/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js index a94a758a..6f6d69e 100644 --- a/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js +++ b/ui/file_manager/file_manager/foreground/js/file_transfer_controller_unittest.js
@@ -11,6 +11,11 @@ /** @type {!DirectoryTree} */ let directoryTree; +/** @type {!FileSelectionHandler} */ +let selectionHandler; + +/** @type {!VolumeManager} */ +let volumeManager; /** * Mock chrome APIs. * @type {!Object} @@ -52,6 +57,7 @@ // Mock LoadTimeData strings. window.loadTimeData.getString = id => id; window.loadTimeData.getBoolean = id => false; + window.loadTimeData.data = {}; // Mock chome APIs. mockChrome = { @@ -86,10 +92,10 @@ const directoryModel = createFakeDirectoryModel(); // Fake VolumeManager. - const volumeManager = new MockVolumeManager(); + volumeManager = new MockVolumeManager(); // Fake FileSelectionHandler. - const selectionHandler = new FakeFileSelectionHandler(); + selectionHandler = new FakeFileSelectionHandler(); // Fake HistoryLoader. const historyLoader = /** @type {!importer.HistoryLoader} */ ({ @@ -188,3 +194,39 @@ assertEquals(crInput, document.activeElement); assertFalse(fileTransferController.isDocumentWideEvent_()); } + +/** + * Tests canCutOrDrag() respects non-modifiable entries like Downloads. + */ +function testCanMoveDownloads() { + // Item 1 of the volume info list should be Downloads volume type. + assertEquals( + VolumeManagerCommon.VolumeType.DOWNLOADS, + volumeManager.volumeInfoList.item(1).volumeType); + + // Create a downloads folder inside the item. + const myFilesVolume = volumeManager.volumeInfoList.item(1); + const myFilesMockFs = + /** @type {!MockFileSystem} */ (myFilesVolume.fileSystem); + + myFilesMockFs.populate([ + '/Downloads/', + '/otherFolder/', + ]); + const downloadsEntry = myFilesMockFs.entries['/Downloads']; + const otherFolderEntry = myFilesMockFs.entries['/otherFolder']; + + assertTrue(!!downloadsEntry); + assertTrue(!!otherFolderEntry); + + selectionHandler = + /** @type {!FakeFileSelectionHandler} */ (selectionHandler); + + // Downloads can't be cut. + selectionHandler.updateSelection([downloadsEntry], []); + assertFalse(fileTransferController.canCutOrDrag()); + + // otherFolder can be cut. + selectionHandler.updateSelection([otherFolderEntry], []); + assertTrue(fileTransferController.canCutOrDrag()); +}
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata.js b/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata.js index 5bc9fd3b6..9e4ed40 100644 --- a/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata.js +++ b/ui/file_manager/file_manager/foreground/js/metadata/mock_metadata.js
@@ -16,16 +16,33 @@ * @public @const {Object} */ this.properties = initial_properties; + + /** + * Per entry properties, which can be set by a test. + * @private @const {Map<string, Object>} + */ + this.propertiesMap_ = new Map(); } /** @override */ - get() { - return Promise.resolve([this.properties]); + get(entries) { + return Promise.resolve(this.getCache(entries)); } /** @override */ - getCache() { - return [this.properties]; + getCache(entries) { + return entries.map( + entry => this.propertiesMap_.has(entry.toURL()) ? + this.propertiesMap_.get(entry.toURL()) : + this.properties); + } + + /** + * @param {Entry} entry + * @param {Object} properties + */ + set(entry, properties) { + this.propertiesMap_.set(entry.toURL(), properties); } /** @override */
diff --git a/ui/file_manager/file_manager/foreground/js/mock_directory_model.js b/ui/file_manager/file_manager/foreground/js/mock_directory_model.js index 0ae06d7..ecfbe3a1d 100644 --- a/ui/file_manager/file_manager/foreground/js/mock_directory_model.js +++ b/ui/file_manager/file_manager/foreground/js/mock_directory_model.js
@@ -73,6 +73,10 @@ opt_callback(); } } + + isReadOnly() { + return false; + } } const model = /** @type {!Object} */ (new FakeDirectoryModel());
diff --git a/ui/file_manager/integration_tests/file_manager/drive_specific.js b/ui/file_manager/integration_tests/file_manager/drive_specific.js index 947120fb..17c33cf 100644 --- a/ui/file_manager/integration_tests/file_manager/drive_specific.js +++ b/ui/file_manager/integration_tests/file_manager/drive_specific.js
@@ -258,6 +258,71 @@ }; /** + * Tests that pinning hosted files without the required extensions is disabled, + * and that it does not affect multiple selections with non-hosted files. + */ +testcase.drivePinHosted = async () => { + const appId = await setupAndWaitUntilReady(RootPath.DRIVE); + + // Select Test Document.gdoc. + await remoteCall.waitAndClickElement( + appId, '#file-list [file-name="Test Document.gdoc"]'); + await remoteCall.waitForElement( + appId, '[file-name="Test Document.gdoc"][selected]'); + + // Open the context menu once the file is selected. + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'fakeMouseRightClick', appId, ['.table-row[selected]'])); + + // Check that the pin action is disabled and unticked. + await remoteCall.waitForElement( + appId, + '#file-context-menu:not([hidden]) ' + + '[command="#toggle-pinned"][disabled]:not([checked])'); + + // Additionally select hello.txt. + await remoteCall.waitAndClickElement( + appId, '#file-list [file-name="hello.txt"]', {shift: true}); + await remoteCall.waitForElement(appId, '[file-name="hello.txt"][selected]'); + + // Open the context menu with both files selected. + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'fakeMouseRightClick', appId, ['.table-row[selected]'])); + + // The pin action should be enabled to pin only hello.txt, so select it. + await remoteCall.waitAndClickElement( + appId, + '#file-context-menu:not([hidden]) ' + + '[command="#toggle-pinned"]:not([checked]):not([disabled])'); + + // Wait for the toggle pinned async action to finish, so the next call to + // display context menu is after the action has finished. + await remoteCall.waitForElement(appId, '#file-context-menu[hidden]'); + + // Wait for the pinned action to finish, it's flagged in the file list by + // removing CSS class "dim-offline" and adding class "pinned". + await remoteCall.waitForElementLost( + appId, '#file-list .dim-offline[file-name="hello.txt"]'); + await remoteCall.waitForElement( + appId, '#file-list .pinned[file-name="hello.txt"] .detail-pinned'); + + // Test Document.gdoc should not be pinned however. + await remoteCall.waitForElement( + appId, '#file-list [file-name="Test Document.gdoc"]:not(.pinned)'); + + + // Open the context menu with both files selected. + chrome.test.assertTrue(await remoteCall.callRemoteTestUtil( + 'fakeMouseRightClick', appId, ['.table-row[selected]'])); + + // Check that the pin action is ticked, i.e. the action will unpin the file. + await remoteCall.waitForElement( + appId, + '#file-context-menu:not([hidden]) ' + + '[command="#toggle-pinned"][checked]:not([disabled])'); +}; + +/** * Tests pinning a file to a mobile network. */ testcase.drivePinFileMobileNetwork = async () => {
diff --git a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/InfoBarTest.java b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/InfoBarTest.java index 0545a82..38ab8b9 100644 --- a/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/InfoBarTest.java +++ b/weblayer/browser/android/javatests/src/org/chromium/weblayer/test/InfoBarTest.java
@@ -148,7 +148,6 @@ @Test @SmallTest - @DisabledTest(message = "Flaky - https://crbug.com/1116247") /** * Tests that the infobar container view is removed as part of tab destruction. *