diff --git a/AUTHORS b/AUTHORS index 57b4da73..b7f610c 100644 --- a/AUTHORS +++ b/AUTHORS
@@ -1077,7 +1077,7 @@ LG Electronics, Inc. <*@lge.com> Loongson Technology Corporation Limited. <*@loongson.cn> Macadamian <*@macadamian.com> -Mail.ru Group <*.corp.mail.ru> +Mail.ru Group <*@corp.mail.ru> Mediatek <*@mediatek.com> Microsoft <*@microsoft.com> MIPS Technologies, Inc. <*@mips.com>
diff --git a/BUILD.gn b/BUILD.gn index b80ac2e..50fdcb21 100644 --- a/BUILD.gn +++ b/BUILD.gn
@@ -144,7 +144,6 @@ "//third_party/dawn:dawn_end2end_tests_temp_group", "//third_party/dawn:dawn_unittests_temp_group", "//third_party/pdfium/samples:pdfium_test", - "//third_party/webrtc/rtc_tools:frame_analyzer", "//tools/perf/clear_system_cache", "//tools/polymer:polymer_tools_python_unittests", "//ui/accessibility:accessibility_perftests",
diff --git a/DEPS b/DEPS index 9bec2070..5385587 100644 --- a/DEPS +++ b/DEPS
@@ -172,11 +172,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '12cea8d6c429d06425be97af31db7c31655e5290', + 'skia_revision': '81a8d282d356667aab7bc8c0513da81bb1c5f3c4', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. - 'v8_revision': '500af51db17fa412e5913c8f81c0d729ad5668e4', + 'v8_revision': '29e8c96fb28537121f964b7b261c7dc286dfbf2c', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling swarming_client # and whatever else without interference from each other. @@ -188,7 +188,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '27a3d31d7a9d65bb49b83da404cc4830eb3ce06e', + 'swiftshader_revision': 'd9ed1c2732ba9b1bd36461367d348e3030043a25', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. @@ -243,7 +243,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': 'b47c6e25f94ebbc276390b621980c0e956490861', + 'devtools_frontend_revision': '5cb14a4f300bbee3447fb241b57799429492c694', # 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. @@ -428,7 +428,7 @@ 'packages': [ { 'package': 'chromium/llvm-build-tools/dsymutil', - 'version': 'OWlhXkmj18li3yhJk59Kmjbc5KdgLh56TwCd1qBdzlIC', + 'version': 'M56jPzDv1620Rnm__jTMYS62Zi8rxHVq7yw0qeBFEgkC', } ], 'condition': 'checkout_mac', @@ -871,7 +871,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '48dc2da07f5bb8fd2353d5790f172fa5b4c4f9fe', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a942a9f9a2358e11484e67c9169de0e698be2723', 'condition': 'checkout_linux', }, @@ -896,7 +896,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9ab047e78be34f3345b00c3d71cbfcbbe110ab3b', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '72a245e4c678f478bf7e1961cae8b2ba5bfa93bf', 'src/third_party/devtools-frontend/src': Var('chromium_git') + '/devtools/devtools-frontend' + '@' + Var('devtools_frontend_revision'), @@ -1311,7 +1311,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '50d2ff30828b5155f3e1f19d98f66def2dd97b09', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f0d1100a7149dce7efa44e42f9c1f0952e6c9ab0', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1512,7 +1512,7 @@ Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'dd55f3ca8f2ea716ca917a4aaf36f0729fe902b1', 'src/third_party/webrtc': - Var('webrtc_git') + '/src.git' + '@' + 'e9f663c8cb8c08501472e2fef8c84dfa98f52b16', + Var('webrtc_git') + '/src.git' + '@' + '7c1fb4156d24a217a497eed6a94ac8cb58e162db', # Wuffs' canonical repository is at github.com/google/wuffs, but we use # Skia's mirror of Wuffs, the same as in upstream Skia's DEPS file. @@ -1579,7 +1579,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@12e6d18c4860140a01518d5f269976319010b9f1', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@275467d3f177738333504b9d2ba68e6245494ae4', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/apk/BUILD.gn b/android_webview/apk/BUILD.gn index 2ffcbb4f..5fbd614 100644 --- a/android_webview/apk/BUILD.gn +++ b/android_webview/apk/BUILD.gn
@@ -52,6 +52,7 @@ "//android_webview:common_crash_java", "//base:base_java", "//components/minidump_uploader:minidump_uploader_java", + "//third_party/android_deps:androidx_annotation_annotation_java", "//ui/android:ui_java", ] android_manifest_for_lint = system_webview_android_manifest
diff --git a/android_webview/apk/java/AndroidManifest.xml b/android_webview/apk/java/AndroidManifest.xml index 6ad7012..6a25f8f 100644 --- a/android_webview/apk/java/AndroidManifest.xml +++ b/android_webview/apk/java/AndroidManifest.xml
@@ -33,7 +33,7 @@ <!--suppress HardcodedText --> <activity android:name="org.chromium.android_webview.devui.MainActivity" android:label="WebView DevTools" - android:theme="@android:style/Theme.DeviceDefault" + android:theme="@style/Theme.DevUi.DayNight" android:launchMode="singleTask" android:process=":webview_apk"> {# Explicit process required for monochrome compatibility. #} <intent-filter> @@ -43,7 +43,7 @@ </activity> <activity android:name="org.chromium.android_webview.devui.CrashesListActivity" android:label="WebView Crashes" - android:theme="@android:style/Theme.DeviceDefault" + android:theme="@style/Theme.DevUi.DayNight" android:launchMode="singleTop" android:process=":webview_apk"> {# Explicit process required for monochrome compatibility. #} </activity>
diff --git a/android_webview/apk/java/res_devui/layout/activity_crashes_list.xml b/android_webview/apk/java/res_devui/layout/activity_crashes_list.xml index 67850b9..c07aac7 100644 --- a/android_webview/apk/java/res_devui/layout/activity_crashes_list.xml +++ b/android_webview/apk/java/res_devui/layout/activity_crashes_list.xml
@@ -7,7 +7,6 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/activity_crashes_list" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> @@ -16,16 +15,23 @@ android:id="@+id/crashes_summary_textview" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="#A9A9A9" - android:textColor="#FFFFFF" - android:textSize="20sp" - android:paddingBottom="5sp" - android:paddingTop="5sp"/> + android:paddingTop="16dp" + android:paddingBottom="16dp" + android:paddingStart="10dp" + android:paddingEnd="10dp" + android:textAppearance="?android:attr/textAppearanceLarge"/> - <ListView + <!-- horizontal divider --> + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:background="?android:attr/listDivider"/> + + <!-- child divider is transparent (hidden) --> + <ExpandableListView android:id="@+id/crashes_list" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="25dp"/> + android:childDivider="#00000000"/> </LinearLayout>
diff --git a/android_webview/apk/java/res_devui/layout/activity_main.xml b/android_webview/apk/java/res_devui/layout/activity_main.xml index e8ce823..12de7ef 100644 --- a/android_webview/apk/java/res_devui/layout/activity_main.xml +++ b/android_webview/apk/java/res_devui/layout/activity_main.xml
@@ -7,7 +7,6 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/activity_main" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
diff --git a/android_webview/apk/java/res_devui/layout/crashes_list_item_body.xml b/android_webview/apk/java/res_devui/layout/crashes_list_item_body.xml new file mode 100644 index 0000000..4c8830d --- /dev/null +++ b/android_webview/apk/java/res_devui/layout/crashes_list_item_body.xml
@@ -0,0 +1,47 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="2dp" + android:paddingBottom="2dp" + android:orientation="vertical"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="?android:attr/expandableListPreferredItemPaddingLeft" + android:paddingEnd="100dp" + android:orientation="vertical"> + + <include layout="@layout/two_line_sublist_item" + android:id="@+id/variations"/> + + <include layout="@layout/two_line_sublist_item" + android:id="@+id/upload_status"/> + + <!--suppress HardcodedText --> + <Button + android:id="@+id/crash_report_button" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:text="File bug report" + android:textAllCaps="false" /> + + </LinearLayout> + + <!-- horizontal divider --> + <View + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginTop="16dp" + android:background="?android:attr/listDivider"/> + +</LinearLayout> \ No newline at end of file
diff --git a/android_webview/apk/java/res_devui/layout/crashes_list_item_header.xml b/android_webview/apk/java/res_devui/layout/crashes_list_item_header.xml new file mode 100644 index 0000000..23290580a --- /dev/null +++ b/android_webview/apk/java/res_devui/layout/crashes_list_item_header.xml
@@ -0,0 +1,28 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="?android:attr/expandableListPreferredItemPaddingLeft" + android:paddingTop="16dp" + android:paddingBottom="16dp" + android:gravity="center" + android:orientation="horizontal"> + + <!--suppress HardcodedText --> + <ImageView + android:layout_height="35dp" + android:layout_width="35dp" + android:id="@+id/crash_package_icon" + android:layout_marginEnd="2dp" + android:contentDescription="package icon"/> + + <include layout="@layout/two_line_list_item" + android:id="@+id/crash_header"/> + +</LinearLayout> \ No newline at end of file
diff --git a/android_webview/apk/java/res_devui/layout/crashes_list_row.xml b/android_webview/apk/java/res_devui/layout/crashes_list_row.xml deleted file mode 100644 index 00feca5..0000000 --- a/android_webview/apk/java/res_devui/layout/crashes_list_row.xml +++ /dev/null
@@ -1,41 +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. ---> - -<LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/crash_list_row" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="15dp" - android:orientation="vertical"> - - <TextView - android:id="@+id/crash_info_label" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:textIsSelectable="true" - android:textStyle="bold" - android:textSize="16sp" - android:paddingBottom="2dp" - android:paddingTop="2dp" - android:background="#d3d3d3"/> - - <TextView - android:id="@+id/crash_info_textview" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginTop="5dp" - android:textIsSelectable="true"/> - - <!--suppress HardcodedText --> - <Button - android:id="@+id/crash_report_button" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="Provide more info"/> - -</LinearLayout>
diff --git a/android_webview/apk/java/res_devui/layout/two_line_list_item.xml b/android_webview/apk/java/res_devui/layout/two_line_list_item.xml new file mode 100644 index 0000000..bdfb55a --- /dev/null +++ b/android_webview/apk/java/res_devui/layout/two_line_list_item.xml
@@ -0,0 +1,35 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="2dp" + android:paddingBottom="2dp" + android:paddingStart="?android:attr/listPreferredItemPaddingStart" + android:paddingEnd="?android:attr/listPreferredItemPaddingEnd" + android:mode="twoLine" + android:orientation="vertical"> + + <TextView android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textStyle="bold" + android:textAlignment="viewStart" + android:paddingTop="4dp" + android:paddingBottom="4dp"/> + + <TextView android:id="@android:id/text2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textAlignment="viewStart" + android:paddingTop="4dp" + android:paddingBottom="4dp"/> + +</LinearLayout> \ No newline at end of file
diff --git a/android_webview/apk/java/res_devui/layout/two_line_sublist_item.xml b/android_webview/apk/java/res_devui/layout/two_line_sublist_item.xml new file mode 100644 index 0000000..60131f9 --- /dev/null +++ b/android_webview/apk/java/res_devui/layout/two_line_sublist_item.xml
@@ -0,0 +1,33 @@ +<?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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingStart="2dp" + android:paddingEnd="2dp" + android:mode="twoLine" + android:orientation="vertical"> + + <TextView android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceListItem" + android:textStyle="bold" + android:textAlignment="viewStart" + android:paddingTop="4dp" + android:paddingBottom="4dp"/> + + <TextView android:id="@android:id/text2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textAlignment="viewStart" + android:paddingTop="4dp" + android:paddingBottom="4dp"/> + +</LinearLayout> \ No newline at end of file
diff --git a/android_webview/apk/java/res_devui/menu/crashes_options_menu.xml b/android_webview/apk/java/res_devui/menu/crashes_options_menu.xml index bd91e392..3690c1b7 100644 --- a/android_webview/apk/java/res_devui/menu/crashes_options_menu.xml +++ b/android_webview/apk/java/res_devui/menu/crashes_options_menu.xml
@@ -5,8 +5,7 @@ LICENSE file. --> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:app="http://schemas.android.com/apk/res-auto"> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:id="@+id/crashes_menu"> <!--suppress HardcodedText --> <item
diff --git a/android_webview/apk/java/res_devui/values-night/styles.xml b/android_webview/apk/java/res_devui/values-night/styles.xml new file mode 100644 index 0000000..fde482f2 --- /dev/null +++ b/android_webview/apk/java/res_devui/values-night/styles.xml
@@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="Theme.DevUi.DayNight" parent="@android:style/Theme.Material" /> +</resources> \ No newline at end of file
diff --git a/android_webview/apk/java/res_devui/values/styles.xml b/android_webview/apk/java/res_devui/values/styles.xml new file mode 100644 index 0000000..1140bf2 --- /dev/null +++ b/android_webview/apk/java/res_devui/values/styles.xml
@@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="Theme.DevUi.DayNight" parent="@android:style/Theme.Material.Light.DarkActionBar" /> +</resources> \ No newline at end of file
diff --git a/android_webview/apk/java/src/org/chromium/android_webview/devui/CrashesListActivity.java b/android_webview/apk/java/src/org/chromium/android_webview/devui/CrashesListActivity.java index a1a018a..6604fd8 100644 --- a/android_webview/apk/java/src/org/chromium/android_webview/devui/CrashesListActivity.java +++ b/android_webview/apk/java/src/org/chromium/android_webview/devui/CrashesListActivity.java
@@ -6,19 +6,23 @@ import android.app.Activity; import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; -import android.text.SpannableStringBuilder; -import android.text.style.StyleSpan; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; +import android.widget.BaseExpandableListAdapter; import android.widget.Button; -import android.widget.ListView; +import android.widget.ExpandableListView; +import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import org.chromium.android_webview.common.crash.CrashInfo; import org.chromium.android_webview.common.crash.CrashInfo.UploadState; import org.chromium.android_webview.devui.util.NavigationMenuHelper; @@ -35,10 +39,12 @@ // Max number of crashes to show in the crashes list. private static final int MAX_CRASHES_NUMBER = 20; - private ListView mCrashListView; private TextView mCrashesSummaryView; + private BaseExpandableListAdapter mCrashListViewAdapter; private WebViewCrashInfoCollector mCrashCollector; + private List<CrashInfo> mCrashInfoList; + private static final String CRASH_REPORT_TEMPLATE = "" + "IMPORTANT: Your crash has already been automatically reported to our crash system. " + "You only need to fill this out if you can share more information like steps to " @@ -76,40 +82,87 @@ setContentView(R.layout.activity_crashes_list); - mCrashListView = findViewById(R.id.crashes_list); mCrashesSummaryView = findViewById(R.id.crashes_summary_textview); mCrashCollector = new WebViewCrashInfoCollector(); + mCrashListViewAdapter = new CrashListExpandableAdapter(); + // initialize the crash list before setting the list adapter. updateCrashesList(); + + ExpandableListView crashListView = findViewById(R.id.crashes_list); + crashListView.setAdapter(mCrashListViewAdapter); } /** - * Adapter to create crashes list rows from a list of CrashInfo. + * Adapter to create crashes list items from a list of CrashInfo. */ - private class CrashListAdapter extends ArrayAdapter<CrashInfo> { - private final List<CrashInfo> mCrashInfoList; - - public CrashListAdapter(List<CrashInfo> crashInfoList) { - super(CrashesListActivity.this, R.layout.crashes_list_row, crashInfoList); - mCrashInfoList = crashInfoList; - } - + private class CrashListExpandableAdapter extends BaseExpandableListAdapter { + // Group View which is used as header for a crash in crashes list. + // We show: + // - Icon of the app where the crash happened. + // - Package name of the app where the crash happened. + // - Time when the crash happened. @Override - public View getView(int position, View view, ViewGroup parent) { + public View getGroupView( + int groupPosition, boolean isExpanded, View view, ViewGroup parent) { // If the the old view is already created then reuse it, else create a new one by layout // inflation. if (view == null) { - view = getLayoutInflater().inflate(R.layout.crashes_list_row, null, true); + view = getLayoutInflater().inflate(R.layout.crashes_list_item_header, null); } - TextView label = view.findViewById(R.id.crash_info_label); - TextView infoTextView = view.findViewById(R.id.crash_info_textview); + CrashInfo crashInfo = (CrashInfo) getGroup(groupPosition); + + ImageView packageIcon = view.findViewById(R.id.crash_package_icon); + String packageName; + if (crashInfo.packageName == null) { + // This can happen if crash log file where we keep crash info is cleared but other + // log files like upload logs still exist. + packageName = "unknown app"; + packageIcon.setImageResource(android.R.drawable.sym_def_app_icon); + } else { + packageName = crashInfo.packageName; + try { + Drawable icon = getPackageManager().getApplicationIcon(packageName); + packageIcon.setImageDrawable(icon); + } catch (PackageManager.NameNotFoundException e) { + // This can happen if the app was uninstalled after the crash was recorded. + packageIcon.setImageResource(android.R.drawable.sym_def_app_icon); + } + } + setTwoLineListItemText(view.findViewById(R.id.crash_header), packageName, + new Date(crashInfo.captureTime).toString()); + + return view; + } + + // Child View where more info about the crash is shown: + // - Variation keys for the crash. + // - Crash report upload status. + @Override + public View getChildView(int groupPosition, final int childPosition, boolean isLastChild, + View view, ViewGroup parent) { + // If the the old view is already created then reuse it, else create a new one by layout + // inflation. + if (view == null) { + view = getLayoutInflater().inflate(R.layout.crashes_list_item_body, null); + } + + CrashInfo crashInfo = (CrashInfo) getChild(groupPosition, childPosition); + // Variations keys + setTwoLineListItemText(view.findViewById(R.id.variations), "Variations", + crashInfo.variations == null ? "Not available" + : crashInfo.variations.toString()); + // Upload info + String uploadState = uploadStateString(crashInfo.uploadState); + String uploadInfo = null; + if (crashInfo.uploadState == UploadState.UPLOADED) { + uploadInfo = new Date(crashInfo.uploadTime).toString(); + uploadInfo += "\nID: " + crashInfo.uploadId; + } + setTwoLineListItemText(view.findViewById(R.id.upload_status), uploadState, uploadInfo); + Button button = view.findViewById(R.id.crash_report_button); - - CrashInfo crashInfo = mCrashInfoList.get(position); - label.setText(getCrashInfoLabelText(crashInfo)); - infoTextView.setText(crashInfoToString(crashInfo)); - // Report button is only clickable if the crash report is uploaded. if (crashInfo.uploadState == UploadState.UPLOADED) { button.setEnabled(true); @@ -123,70 +176,110 @@ return view; } - private String getCrashInfoLabelText(CrashInfo crashInfo) { - String status = - crashInfo.uploadState == null ? "UNKOWN" : crashInfo.uploadState.toString(); - return String.format(Locale.US, "Crash (%s) - [%s]", crashInfo.localId, status); + @Override + public boolean isChildSelectable(int groupPosition, int childPosition) { + return true; } - /** - * Convert CrashInfo object to a string to show it in a TexView. - * Field name is in BOLD while the value is not. - */ - private SpannableStringBuilder crashInfoToString(CrashInfo crashInfo) { - SpannableStringBuilder builder = new SpannableStringBuilder(); - if (crashInfo.uploadId != null) { - builder.append("upload ID: ", new StyleSpan(android.graphics.Typeface.BOLD), 0) - .append(crashInfo.uploadId) - .append("\n"); - } - if (crashInfo.uploadTime >= 0) { - builder.append("upload time: ", new StyleSpan(android.graphics.Typeface.BOLD), 0) - .append(new Date(crashInfo.uploadTime).toString()) - .append("\n"); - } - if (crashInfo.captureTime >= 0) { - builder.append("capture time: ", new StyleSpan(android.graphics.Typeface.BOLD), 0) - .append(new Date(crashInfo.captureTime).toString()) - .append("\n"); - } - if (crashInfo.packageName != null) { - builder.append("app package name: ", new StyleSpan(android.graphics.Typeface.BOLD), - 0) - .append(crashInfo.packageName) - .append("\n"); - } - if (crashInfo.variations != null) { - builder.append("variations: ", new StyleSpan(android.graphics.Typeface.BOLD), 0) - .append(crashInfo.variations.toString()) - .append("\n"); - } - return builder; + @Override + public Object getGroup(int groupPosition) { + return mCrashInfoList.get(groupPosition); } - // Build a report uri to open an issue on https://bugs.chromium.org/p/chromium/issues/entry. - // It uses WebView Bugs Template and adds "User-Submitted" Label. - // It adds the upload id at the end of the template and populates the Application package - // name field. - // TODO(https://crbug.com/991594) populate more fields in the template. - private Uri getReportUri(CrashInfo crashInfo) { - return new Uri.Builder() - .scheme("https") - .authority("bugs.chromium.org") - .path("/p/chromium/issues/entry") - .appendQueryParameter("template", "Webview+Bugs") - .appendQueryParameter("comment", - String.format(Locale.US, CRASH_REPORT_TEMPLATE, crashInfo.uploadId)) - .appendQueryParameter("labels", "User-Submitted") - .build(); + @Override + public Object getChild(int groupPosition, int childPosition) { + return mCrashInfoList.get(groupPosition); + } + + @Override + public long getGroupId(int groupPosition) { + // Hash code of local id is unique per crash info object. + return ((CrashInfo) getGroup(groupPosition)).localId.hashCode(); + } + + @Override + public long getChildId(int groupPosition, int childPosition) { + // Child ID refers to a piece of info in a particular crash report. It is stable + // since we don't change the order we show this info in runtime and currently we show + // all information in only one child item. + return childPosition; + } + + @Override + public boolean hasStableIds() { + // Stable IDs mean both getGroupId and getChildId return stable IDs for each group and + // child i.e: an ID always refers to the same object. See getGroupId and getChildId for + // why the IDs are stable. + return true; + } + + @Override + public int getChildrenCount(int groupPosition) { + // Crash info is shown in one child item. + return 1; + } + + @Override + public int getGroupCount() { + return mCrashInfoList.size(); + } + } + + // Build a report uri to open an issue on https://bugs.chromium.org/p/chromium/issues/entry. + // It uses WebView Bugs Template and adds "User-Submitted" Label. + // It adds the upload id at the end of the template and populates the Application package + // name field. + // TODO(https://crbug.com/991594) populate more fields in the template. + private static Uri getReportUri(CrashInfo crashInfo) { + return new Uri.Builder() + .scheme("https") + .authority("bugs.chromium.org") + .path("/p/chromium/issues/entry") + .appendQueryParameter("template", "Webview+Bugs") + .appendQueryParameter("comment", + String.format(Locale.US, CRASH_REPORT_TEMPLATE, crashInfo.uploadId)) + .appendQueryParameter("labels", "User-Submitted") + .build(); + } + + private static String uploadStateString(UploadState uploadState) { + switch (uploadState) { + case UPLOADED: + return "Uploaded"; + case PENDING: + case PENDING_USER_REQUESTED: + return "Pending upload"; + case SKIPPED: + return "Skipped upload"; + } + return null; + } + + // Helper method to find and set text for two line list item. If a null String is passed, the + // relevant TextView will be hidden. + private static void setTwoLineListItemText( + @NonNull View view, @Nullable String title, @Nullable String subtitle) { + TextView titleView = view.findViewById(android.R.id.text1); + TextView subtitleView = view.findViewById(android.R.id.text2); + if (titleView != null) { + titleView.setVisibility(View.VISIBLE); + titleView.setText(title); + } else { + titleView.setVisibility(View.GONE); + } + if (subtitle != null) { + subtitleView.setVisibility(View.VISIBLE); + subtitleView.setText(subtitle); + } else { + subtitleView.setVisibility(View.GONE); } } private void updateCrashesList() { - List<CrashInfo> crashesList = mCrashCollector.loadCrashesInfo(MAX_CRASHES_NUMBER); - mCrashListView.setAdapter(new CrashListAdapter(crashesList)); - - mCrashesSummaryView.setText(String.format(Locale.US, "Crashes (%d)", crashesList.size())); + mCrashInfoList = mCrashCollector.loadCrashesInfo(MAX_CRASHES_NUMBER); + mCrashListViewAdapter.notifyDataSetChanged(); + mCrashesSummaryView.setText( + String.format(Locale.US, "Crashes (%d)", mCrashInfoList.size())); } @Override
diff --git a/android_webview/apk/java/src/org/chromium/android_webview/devui/MainActivity.java b/android_webview/apk/java/src/org/chromium/android_webview/devui/MainActivity.java index 2ff87b08..6f1e6fc 100644 --- a/android_webview/apk/java/src/org/chromium/android_webview/devui/MainActivity.java +++ b/android_webview/apk/java/src/org/chromium/android_webview/devui/MainActivity.java
@@ -94,7 +94,7 @@ private final InfoItem[] mItems; public InfoListAdapter(InfoItem[] items) { - super(MainActivity.this, android.R.layout.simple_list_item_2, items); + super(MainActivity.this, R.layout.two_line_list_item, items); mItems = items; } @@ -103,7 +103,7 @@ // If the the old view is already created then reuse it, else create a new one by layout // inflation. if (view == null) { - view = getLayoutInflater().inflate(android.R.layout.simple_list_item_2, null, true); + view = getLayoutInflater().inflate(R.layout.two_line_list_item, null, true); } InfoItem item = mItems[position];
diff --git a/android_webview/java/src/org/chromium/android_webview/FindAddress.java b/android_webview/java/src/org/chromium/android_webview/FindAddress.java index 781f1ec..fcfc512 100644 --- a/android_webview/java/src/org/chromium/android_webview/FindAddress.java +++ b/android_webview/java/src/org/chromium/android_webview/FindAddress.java
@@ -250,8 +250,9 @@ private static boolean checkHouseNumber(String houseNumber) { // Make sure that there are at most 5 digits. int digitCount = 0; - for (int i = 0; i < houseNumber.length(); ++i) + for (int i = 0; i < houseNumber.length(); ++i) { if (Character.isDigit(houseNumber.charAt(i))) ++digitCount; + } if (digitCount > 5) return false; // Make sure that any ordinals are valid. @@ -324,8 +325,9 @@ if (stateMatch == null) return false; // Work out the index of the state, based on which group matched. int stateIndex = stateMatch.groupCount(); - while (stateIndex > 0) + while (stateIndex > 0) { if (stateMatch.group(stateIndex--) != null) break; + } return sZipCodeRe.matcher(zipCode).matches() && sStateZipCodeRanges[stateIndex].matches(zipCode); }
diff --git a/android_webview/lib/aw_main_delegate.cc b/android_webview/lib/aw_main_delegate.cc index 3b7512b1..8175c905 100644 --- a/android_webview/lib/aw_main_delegate.cc +++ b/android_webview/lib/aw_main_delegate.cc
@@ -184,8 +184,8 @@ // WebView isn't compatible with OOP-D. features.DisableIfNotSet(::features::kVizDisplayCompositor); - // WebView does not support AndroidOverlay yet for video overlays. - features.DisableIfNotSet(media::kUseAndroidOverlay); + // WebView does not support overlay fullscreen yet for video overlays. + features.DisableIfNotSet(media::kOverlayFullscreenVideo); // WebView doesn't support embedding CompositorFrameSinks which is needed // for UseSurfaceLayerForVideo feature. https://crbug.com/853832
diff --git a/ash/accelerators/accelerator_confirmation_dialog.cc b/ash/accelerators/accelerator_confirmation_dialog.cc index cd0d2cf..1899c456 100644 --- a/ash/accelerators/accelerator_confirmation_dialog.cc +++ b/ash/accelerators/accelerator_confirmation_dialog.cc
@@ -40,16 +40,14 @@ AddChildView(std::make_unique<views::Label>( l10n_util::GetStringUTF16(dialog_text_id))); - // Parent the dialog widget to the LockSystemModalContainer, or - // OverlayContainer to ensure that it will get displayed on respective - // lock/signin or OOBE screen. + // Parent the dialog widget to the LockSystemModalContainer to ensure that it + // will get displayed on respective lock/signin or OOBE screen. SessionControllerImpl* session_controller = Shell::Get()->session_controller(); int container_id = kShellWindowId_SystemModalContainer; - if (session_controller->GetSessionState() == - session_manager::SessionState::OOBE) { - container_id = kShellWindowId_OverlayContainer; - } else if (session_controller->IsUserSessionBlocked()) { + if (session_controller->IsUserSessionBlocked() || + session_controller->GetSessionState() == + session_manager::SessionState::OOBE) { container_id = kShellWindowId_LockSystemModalContainer; }
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc index 01ab350..8a064458 100644 --- a/ash/app_list/app_list_controller_impl_unittest.cc +++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -28,6 +28,8 @@ #include "ash/public/cpp/window_properties.h" #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_layout_manager.h" +#include "ash/shelf/shelf_view.h" +#include "ash/shelf/shelf_view_test_api.h" #include "ash/shelf/shelf_widget.h" #include "ash/shell.h" #include "ash/system/unified/unified_system_tray_test_api.h" @@ -473,6 +475,52 @@ // Tests with both hotseat disabled and enabled. INSTANTIATE_TEST_SUITE_P(, HotseatAppListControllerImplTest, testing::Bool()); +// Verifies that the pinned app should still show after canceling the drag from +// AppsGridView to Shelf (https://crbug.com/1021768). +TEST_P(HotseatAppListControllerImplTest, DragItemFromAppsGridView) { + // Turn on the tablet mode. + Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); + EXPECT_TRUE(IsTabletMode()); + + Shelf* const shelf = GetPrimaryShelf(); + + // Add icons with the same app id to Shelf and AppsGridView respectively. + ShelfViewTestAPI shelf_view_test_api(shelf->GetShelfViewForTesting()); + std::string app_id = shelf_view_test_api.AddItem(TYPE_PINNED_APP).app_id; + Shell::Get()->app_list_controller()->GetModel()->AddItem( + std::make_unique<AppListItem>(app_id)); + + AppsGridView* apps_grid_view = GetAppListView() + ->app_list_main_view() + ->contents_view() + ->GetAppsContainerView() + ->apps_grid_view(); + AppListItemView* app_list_item_view = + test::AppsGridViewTestApi(apps_grid_view).GetViewAtIndex(GridIndex(0, 0)); + views::View* shelf_icon_view = + shelf->GetShelfViewForTesting()->view_model()->view_at(0); + + // Drag the app icon from AppsGridView to Shelf. Then move the icon back to + // AppsGridView before drag ends. + GetEventGenerator()->MoveMouseTo( + app_list_item_view->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->PressLeftButton(); + app_list_item_view->FireMouseDragTimerForTest(); + GetEventGenerator()->MoveMouseTo( + shelf_icon_view->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->MoveMouseTo( + apps_grid_view->GetBoundsInScreen().CenterPoint()); + GetEventGenerator()->ReleaseLeftButton(); + + // The icon's opacity updates at the end of animation. + shelf_view_test_api.RunMessageLoopUntilAnimationsDone(); + + // The icon is pinned before drag starts. So the shelf icon should show in + // spite that drag is canceled. + EXPECT_TRUE(shelf_icon_view->GetVisible()); + EXPECT_EQ(1.0f, shelf_icon_view->layer()->opacity()); +} + // Tests for HomeScreenDelegate::GetInitialAppListItemScreenBoundsForWindow // implemtenation. TEST_P(HotseatAppListControllerImplTest, GetItemBoundsForWindow) {
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc index 36af280..7eb8558 100644 --- a/ash/app_list/views/app_list_item_view.cc +++ b/ash/app_list/views/app_list_item_view.cc
@@ -803,6 +803,10 @@ layer()->SetFillsBoundsOpaquely(false); } +void AppListItemView::FireMouseDragTimerForTest() { + mouse_drag_timer_.FireNow(); +} + void AppListItemView::AnimationProgressed(const gfx::Animation* animation) { DCHECK(!is_folder_);
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h index 49c865d4..5d38c4f6 100644 --- a/ash/app_list/views/app_list_item_view.h +++ b/ash/app_list/views/app_list_item_view.h
@@ -136,6 +136,8 @@ // Ensures this item view has its own layer. void EnsureLayer(); + void FireMouseDragTimerForTest(); + bool is_folder() const { return is_folder_; } private:
diff --git a/ash/display/display_manager_unittest.cc b/ash/display/display_manager_unittest.cc index f6ec4953..d88cc4a 100644 --- a/ash/display/display_manager_unittest.cc +++ b/ash/display/display_manager_unittest.cc
@@ -4612,4 +4612,24 @@ } } +// Test that exiting mirror mode in tablet mode with a fullscreen window +// does not cause a crash (crbug.com/1021662). +TEST_F(DisplayManagerTest, ExitMirrorModeInTabletMode) { + // Simulate a tablet with and external display connected. + display::test::DisplayManagerTestApi(display_manager()) + .SetFirstDisplayAsInternalDisplay(); + UpdateDisplay("800x600,800x600"); + Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(display_manager()->IsInSoftwareMirrorMode()); + + // Create a window to force in-app shelf. + std::unique_ptr<aura::Window> window = CreateTestWindow(); + + // Exit mirror mode. + display_manager()->SetMirrorMode(display::MirrorMode::kOff, base::nullopt); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(display_manager()->IsInSoftwareMirrorMode()); +} + } // namespace ash
diff --git a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc index 6d1802a..57cf031 100644 --- a/ash/home_screen/drag_window_from_shelf_controller_unittest.cc +++ b/ash/home_screen/drag_window_from_shelf_controller_unittest.cc
@@ -518,7 +518,7 @@ // Test that if drag is cancelled, overview should be dismissed and other // hidden windows should restore to its previous visibility state. -// Flaky on ChromeOS. https://crbug.com/1022319 +// TODO(crbug.com/1022319): flaky. TEST_F(DragWindowFromShelfControllerTest, DISABLED_CancelDragDismissOverview) { auto window3 = CreateTestWindow(); auto window2 = CreateTestWindow();
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc index 0147545..ca56b44 100644 --- a/ash/home_screen/home_screen_controller.cc +++ b/ash/home_screen/home_screen_controller.cc
@@ -4,6 +4,7 @@ #include "ash/home_screen/home_screen_controller.h" +#include <memory> #include <vector> #include "ash/home_screen/home_launcher_gesture_handler.h" @@ -12,6 +13,7 @@ #include "ash/public/cpp/ash_features.h" #include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/window_properties.h" +#include "ash/scoped_animation_disabler.h" #include "ash/session/session_controller_impl.h" #include "ash/shelf/shelf.h" #include "ash/shell.h" @@ -157,9 +159,6 @@ return true; } - delegate_->OnHomeLauncherTargetPositionChanged(true /* showing */, - display_id); - // First minimize all inactive windows. const bool window_minimized = MinimizeAllWindows(windows, active_windows /*windows_to_ignore*/); @@ -167,8 +166,26 @@ // Animate currently active windows into the home screen - they will be // minimized by WindowTransformToHomeScreenAnimation when the transition // finishes. - if (!active_windows.empty()) { + { + // Disable window animations before updating home launcher target + // position. Calling OnHomeLauncherTargetPositionChanged() can cause + // display work area update, and resulting cross-fade window bounds change + // animation can interfere with WindowTransformToHomeScreenAnimation + // visuals. + // + // TODO(https://crbug.com/1019531): This can be removed once transitions + // between in-app state and home do not cause work area updates. + std::vector<std::unique_ptr<ScopedAnimationDisabler>> animation_disablers; + for (auto* window : active_windows) { + animation_disablers.push_back( + std::make_unique<ScopedAnimationDisabler>(window)); + } + + delegate_->OnHomeLauncherTargetPositionChanged(true /* showing */, + display_id); + } + base::RepeatingClosure window_transforms_callback = base::BarrierClosure( active_windows.size(), base::BindOnce(&HomeScreenController::NotifyHomeLauncherTransitionEnded, @@ -193,8 +210,6 @@ : base::NullCallback()); } } - } else { - delegate_->OnHomeLauncherAnimationComplete(true /*shown*/, display_id); } return window_minimized || !active_windows.empty();
diff --git a/ash/shelf/back_button.cc b/ash/shelf/back_button.cc index 2f0bb5a..4871082 100644 --- a/ash/shelf/back_button.cc +++ b/ash/shelf/back_button.cc
@@ -8,6 +8,8 @@ #include "ash/shelf/shelf.h" #include "ash/shelf/shelf_focus_cycler.h" #include "ash/strings/grit/ash_strings.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/base/l10n/l10n_util.h" @@ -57,6 +59,8 @@ void BackButton::ButtonPressed(views::Button* sender, const ui::Event& event, views::InkDrop* ink_drop) { + base::RecordAction(base::UserMetricsAction("AppList_BackButtonPressed")); + // Send up event as well as down event as ARC++ clients expect this sequence. // TODO: Investigate if we should be using the current modifiers. aura::Window* root_window = GetWidget()->GetNativeWindow()->GetRootWindow();
diff --git a/ash/shelf/home_button.cc b/ash/shelf/home_button.cc index 814f53c..775bc3f 100644 --- a/ash/shelf/home_button.cc +++ b/ash/shelf/home_button.cc
@@ -14,6 +14,8 @@ #include "ash/shell.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/logging.h" +#include "base/metrics/user_metrics.h" +#include "base/metrics/user_metrics_action.h" #include "chromeos/strings/grit/chromeos_strings.h" #include "ui/aura/window.h" #include "ui/base/l10n/l10n_util.h" @@ -85,8 +87,14 @@ void HomeButton::ButtonPressed(views::Button* sender, const ui::Event& event, views::InkDrop* ink_drop) { - Shell::Get()->metrics()->RecordUserMetricsAction( - UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON); + if (Shell::Get()->tablet_mode_controller()->InTabletMode()) { + base::RecordAction( + base::UserMetricsAction("AppList_HomeButtonPressedTablet")); + } else { + base::RecordAction( + base::UserMetricsAction("AppList_HomeButtonPressedClamshell")); + } + const AppListShowSource show_source = event.IsShiftDown() ? kShelfButtonFullscreen : kShelfButton; OnPressed(show_source, event.time_stamp());
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index 7a2e41e7..8815fd6 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -1351,11 +1351,23 @@ if (drag_and_drop_item_pinned_ && cancel) { model_->UnpinAppWithID(drag_and_drop_shelf_id_.app_id); } else if (drag_and_drop_view) { + std::unique_ptr<gfx::AnimationDelegate> animation_delegate; + + if (chromeos::switches::ShouldShowScrollableShelf()) { + // Resets the dragged view's opacity at the end of drag. Otherwise, if + // the app is already pinned on shelf before drag starts, the dragged view + // will be invisible when drag ends. + animation_delegate = std::make_unique<StartFadeAnimationDelegate>( + this, drag_and_drop_view); + } + if (cancel) { // When a hosted drag gets canceled, the item can remain in the same slot // and it might have moved within the bounds. In that case the item need // to animate back to its correct location. AnimateToIdealBounds(); + bounds_animator_->SetAnimationDelegate(drag_and_drop_view, + std::move(animation_delegate)); } else { drag_and_drop_view->SetSize(pre_drag_and_drop_size_); }
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc index 48145fa..e916228 100644 --- a/ash/shelf/shelf_view_unittest.cc +++ b/ash/shelf/shelf_view_unittest.cc
@@ -1440,6 +1440,45 @@ EXPECT_FALSE(tooltip_manager->IsVisible()); } +// Verifies that the time of button press is recorded correctly in clamshell. +TEST_F(ShelfViewTest, HomeButtonMetricsInClamshell) { + const HomeButton* home_button = shelf_view_->shelf_widget()->GetHomeButton(); + + // Make sure we're not showing the app list. + EXPECT_FALSE(home_button->IsShowingAppList()); + + base::UserActionTester user_action_tester; + ASSERT_EQ(0, user_action_tester.GetActionCount( + "AppList_HomeButtonPressedClamshell")); + + GetEventGenerator()->GestureTapAt( + home_button->GetBoundsInScreen().CenterPoint()); + ASSERT_EQ(1, user_action_tester.GetActionCount( + "AppList_HomeButtonPressedClamshell")); + EXPECT_TRUE(home_button->IsShowingAppList()); +} + +// Verifies that the time of button press is recorded correctly in tablet. +TEST_F(ShelfViewTest, HomeButtonMetricsInTablet) { + Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true); + const HomeButton* home_button = shelf_view_->shelf_widget()->GetHomeButton(); + + // Make sure we're not showing the app list. + std::unique_ptr<aura::Window> window = CreateTestWindow(); + wm::ActivateWindow(window.get()); + EXPECT_FALSE(home_button->IsShowingAppList()); + + base::UserActionTester user_action_tester; + ASSERT_EQ( + 0, user_action_tester.GetActionCount("AppList_HomeButtonPressedTablet")); + + GetEventGenerator()->GestureTapAt( + home_button->GetBoundsInScreen().CenterPoint()); + ASSERT_EQ( + 1, user_action_tester.GetActionCount("AppList_HomeButtonPressedTablet")); + EXPECT_TRUE(home_button->IsShowingAppList()); +} + class HotseatShelfViewTest : public ShelfViewTest, public testing::WithParamInterface<bool> { public:
diff --git a/ash/shelf/shelf_widget.cc b/ash/shelf/shelf_widget.cc index 6069039b..b56e16e 100644 --- a/ash/shelf/shelf_widget.cc +++ b/ash/shelf/shelf_widget.cc
@@ -108,6 +108,8 @@ bool CanActivate() const override; void ReorderChildLayers(ui::Layer* parent_layer) override; + void OnWidgetInitialized() override; + void UpdateBackgroundBlur(); void UpdateOpaqueBackground(); void UpdateDragHandle(); @@ -169,8 +171,6 @@ drag_handle_->layer()->SetRoundedCornerRadius( {radius, radius, radius, radius}); drag_handle_->SetSize(kDragHandleSize); - - UpdateOpaqueBackground(); } ShelfWidget::DelegateView::~DelegateView() = default; @@ -211,6 +211,10 @@ parent_layer->StackAtBottom(&opaque_background_); } +void ShelfWidget::DelegateView::OnWidgetInitialized() { + UpdateOpaqueBackground(); +} + void ShelfWidget::DelegateView::UpdateBackgroundBlur() { // Blur only if the background is visible. const bool should_blur_background =
diff --git a/base/android/junit/src/org/chromium/base/task/AsyncTaskThreadTest.java b/base/android/junit/src/org/chromium/base/task/AsyncTaskThreadTest.java index 55dc94bd..5072c573 100644 --- a/base/android/junit/src/org/chromium/base/task/AsyncTaskThreadTest.java +++ b/base/android/junit/src/org/chromium/base/task/AsyncTaskThreadTest.java
@@ -4,11 +4,14 @@ package org.chromium.base.task; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.support.test.filters.SmallTest; +import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; @@ -40,6 +43,9 @@ private static class BlockAndGetFeedDataTask extends AsyncTask<Boolean> { private LinkedBlockingQueue<Boolean> mIncomingQueue = new LinkedBlockingQueue<Boolean>(); private LinkedBlockingQueue<Boolean> mOutgoingQueue = new LinkedBlockingQueue<Boolean>(); + private LinkedBlockingQueue<Boolean> mInterruptedExceptionQueue = + new LinkedBlockingQueue<Boolean>(); + private Boolean mPostExecuteResult; @Override protected Boolean doInBackground() { @@ -51,6 +57,7 @@ @Override protected void onPostExecute(Boolean result) { if (DEBUG) Log.i(TAG, "onPostExecute: " + result); + mPostExecuteResult = result; } public void feedData(Boolean data) { @@ -61,6 +68,7 @@ try { return mIncomingQueue.poll(3, TimeUnit.SECONDS); } catch (InterruptedException e) { + mInterruptedExceptionQueue.add(true); return false; } } @@ -68,8 +76,17 @@ public void blockUntilDoInBackgroundStarts() throws Exception { mOutgoingQueue.poll(3, TimeUnit.SECONDS); } + + public Boolean getPostExecuteResult() { + return mPostExecuteResult; + } + + public LinkedBlockingQueue<Boolean> getInterruptedExceptionQueue() { + return mInterruptedExceptionQueue; + } } + private final BlockAndGetFeedDataTask mTask = new BlockAndGetFeedDataTask(); private final RoboExecutorService mRoboExecutorService = new RoboExecutorService(); private final Scheduler mBackgroundScheduler = Robolectric.getBackgroundThreadScheduler(); @@ -85,42 +102,96 @@ mBackgroundScheduler.pause(); } + @After + public void tearDown() { + // No unexpected interrupted exception. + assertNull(mTask.getInterruptedExceptionQueue().poll()); + Assert.assertTrue(mRoboExecutorService.shutdownNow().isEmpty()); + } + @Test @SmallTest public void testCancel_ReturnsFalseOnceTaskFinishes() throws Exception { - BlockAndGetFeedDataTask task = new BlockAndGetFeedDataTask(); // This test requires robo executor service such that we can run // one background task. - task.executeOnExecutor(mRoboExecutorService); + mTask.executeOnExecutor(mRoboExecutorService); - // We feed the background thread, then cancel. - task.feedData(true); + // Ensure that the background thread is not blocked. + mTask.feedData(true); + mBackgroundScheduler.runOneTask(); // Cannot cancel. The task is already run. - assertFalse(task.cancel(false)); - assertTrue(task.get()); + assertFalse(mTask.cancel(false /* mayInterruptIfRunning */)); + assertTrue(mTask.get()); + assertEquals(Boolean.valueOf(true), mTask.getPostExecuteResult()); } @Test @SmallTest public void testCancel_CanReturnTrueEvenAfterTaskStarts() throws Exception { - BlockAndGetFeedDataTask task = new BlockAndGetFeedDataTask(); - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - // The task has started. - task.blockUntilDoInBackgroundStarts(); + // Wait until the task is started. Note that data is not yet fed. + mTask.blockUntilDoInBackgroundStarts(); // This reflects FutureTask#cancel() behavior. Note that the task is // started but cancel can still return true. - assertTrue(task.cancel(false)); - task.feedData(true); + assertTrue(mTask.cancel(false /* mayInterruptIfRunning */)); - // get() will raise an exception although the task is run. + // Continue the task. + mTask.feedData(true); + + // get() will raise an exception although the task is started. try { - task.get(); + mTask.get(); Assert.fail(); } catch (CancellationException e) { // expected } + assertNull(mTask.getPostExecuteResult()); // onPostExecute did not run. + } + + @Test + @SmallTest + public void testCancel_MayInterrupt_ReturnsFalseOnceTaskFinishes() throws Exception { + // This test requires robo executor service such that we can run + // one background task. + mTask.executeOnExecutor(mRoboExecutorService); + + // Ensure that the background thread is not blocked. + mTask.feedData(true); + + mBackgroundScheduler.runOneTask(); + + // Cannot cancel. The task is already run. + assertFalse(mTask.cancel(true /* mayInterruptIfRunning */)); + assertTrue(mTask.get()); + assertEquals(Boolean.valueOf(true), mTask.getPostExecuteResult()); + } + + @Test + @SmallTest + public void testCancel_MayInterrupt_TaskIsInterrupted() throws Exception { + mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + // Wait until the task is started. Note that data is not yet fed. + mTask.blockUntilDoInBackgroundStarts(); + + // Cancel and interrupt the current task. + assertTrue(mTask.cancel(true /* mayInterruptIfRunning */)); + + // Ensure that the background thread is not blocked. + mTask.feedData(true); + + // get() will raise an exception although the task is started. + try { + mTask.get(); + Assert.fail(); + } catch (CancellationException e) { + // expected + } + assertNull(mTask.getPostExecuteResult()); // onPostExecute did not run. + // Task was interrupted. + assertEquals(Boolean.valueOf(true), mTask.getInterruptedExceptionQueue().poll()); } }
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/AnnotationProcessingUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/AnnotationProcessingUtils.java index 546ff24..d5daa44 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/util/AnnotationProcessingUtils.java +++ b/base/test/android/javatests/src/org/chromium/base/test/util/AnnotationProcessingUtils.java
@@ -192,7 +192,7 @@ * Abstraction to hide differences between Class, Method and Description with regards to their * annotations and what should be analyzed next. */ - private static abstract class AnnotatedNode { + private abstract static class AnnotatedNode { @Nullable abstract AnnotatedNode getParent();
diff --git a/build/android/docs/java_optimization.md b/build/android/docs/java_optimization.md index b8ee80b..e0f0ec7 100644 --- a/build/android/docs/java_optimization.md +++ b/build/android/docs/java_optimization.md
@@ -89,7 +89,7 @@ Helpful links for deobfuscation: * [Internal bits about how mapping files are archived][proguard-site] -* [More detaled deobfuscation instructions][proguard-doc] +* [More detailed deobfuscation instructions][proguard-doc] * [Script for deobfuscating official builds][deob-official] [proguard-site]: http://goto.google.com/chrome-android-proguard
diff --git a/build/android/docs/java_toolchain.md b/build/android/docs/java_toolchain.md index 6a432d3..b8edb46 100644 --- a/build/android/docs/java_toolchain.md +++ b/build/android/docs/java_toolchain.md
@@ -17,7 +17,7 @@ * `android_library()` * `android_java_prebuilt()` -All targets names must end with "_java" so that the build system can distinguish +All target names must end with "_java" so that the build system can distinguish them from non-java targets (or [other variations](https://cs.chromium.org/chromium/src/build/config/android/internal_rules.gni?rcl=ec2c17d7b4e424e060c3c7972842af87343526a1&l=20)). ## From Source to Final Dex @@ -117,7 +117,7 @@ This step happens only when targets have `supports_android = true`. -* [d8] converts `.jar` files contain `.class` files into `.dex.jar` files +* [d8] converts `.jar` files containing `.class` files into `.dex.jar` files containing `.dex` files. * Dexing is incremental - it will reuse dex'ed classes from a previous build if the corresponding `.class` file is unchanged. @@ -287,7 +287,7 @@ * Can be toggle on/off with code comments. ```java // clang-format off - ... non-formated code here ... + ... non-formatted code here ... // clang-format on ``` * Does not work great for multiple annotations or on some lambda expressions,
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index cf7ba58..16110e5 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8897466458026657776 \ No newline at end of file +8897419927696300224 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index e7f9e6f..ee69debb 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8897472768194582624 \ No newline at end of file +8897425289159983392 \ No newline at end of file
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc index 0bb4eec0..3b360a2 100644 --- a/cc/metrics/frame_sequence_tracker.cc +++ b/cc/metrics/frame_sequence_tracker.cc
@@ -17,11 +17,13 @@ // This macro is used with DCHECK to provide addition debug info. #if DCHECK_IS_ON() -#define TRACKER_DCHECK_MSG \ - " in " << kFrameSequenceTrackerTypeNames[this->type_] \ - << " tracker: " << frame_sequence_trace_ << " (" \ - << frame_sequence_trace_.size() << ")"; +#define TRACKER_TRACE_STREAM frame_sequence_trace_ +#define TRACKER_DCHECK_MSG \ + " in " << kFrameSequenceTrackerTypeNames[this->type_] \ + << " tracker: " << frame_sequence_trace_.str() << " (" \ + << frame_sequence_trace_.str().size() << ")"; #else +#define TRACKER_TRACE_STREAM EAT_STREAM_PARAMETERS #define TRACKER_DCHECK_MSG "" #endif @@ -293,7 +295,7 @@ if (ShouldIgnoreBeginFrameSource(args.source_id)) return; - LogFrameSequenceTrace('b'); + TRACKER_TRACE_STREAM << 'b'; UpdateTrackedFrameData(&begin_impl_frame_data_, args.source_id, args.sequence_number); impl_throughput_.frames_expected += @@ -311,7 +313,9 @@ if (ShouldIgnoreBeginFrameSource(args.source_id)) return; - LogFrameSequenceTrace('B'); + TRACKER_TRACE_STREAM << 'B'; + TRACKER_TRACE_STREAM << "(" << begin_main_frame_data_.previous_sequence << "," + << args.sequence_number << ")"; UpdateTrackedFrameData(&begin_main_frame_data_, args.source_id, args.sequence_number); if (first_received_main_sequence_ == 0) @@ -345,7 +349,7 @@ origin_args.sequence_number >= first_received_main_sequence_) { if (last_submitted_main_sequence_ == 0 || origin_args.sequence_number > last_submitted_main_sequence_) { - LogFrameSequenceTrace('S'); + TRACKER_TRACE_STREAM << 'S'; last_submitted_main_sequence_ = origin_args.sequence_number; main_frames_.push_back(frame_token); @@ -381,7 +385,7 @@ return; } - LogFrameSequenceTrace('P'); + TRACKER_TRACE_STREAM << 'P'; TRACE_EVENT_ASYNC_STEP_INTO_WITH_TIMESTAMP0( "cc,benchmark", "FrameSequenceTracker", this, "FramePresented", @@ -457,7 +461,7 @@ ack.sequence_number < begin_impl_frame_data_.previous_sequence) { return; } - LogFrameSequenceTrace('n'); + TRACKER_TRACE_STREAM << 'n'; DCHECK_GT(impl_throughput_.frames_expected, 0u) << TRACKER_DCHECK_MSG; DCHECK_GT(impl_throughput_.frames_expected, impl_throughput_.frames_produced) << TRACKER_DCHECK_MSG; @@ -482,7 +486,9 @@ return; } - LogFrameSequenceTrace('N'); + TRACKER_TRACE_STREAM << 'N'; + TRACKER_TRACE_STREAM << "(" << begin_main_frame_data_.previous_sequence << "," + << args.sequence_number << ")"; DCHECK_GT(main_throughput_.frames_expected, 0u) << TRACKER_DCHECK_MSG; DCHECK_GT(main_throughput_.frames_expected, main_throughput_.frames_produced) << TRACKER_DCHECK_MSG;
diff --git a/cc/metrics/frame_sequence_tracker.h b/cc/metrics/frame_sequence_tracker.h index 449dcc1..e3de825 100644 --- a/cc/metrics/frame_sequence_tracker.h +++ b/cc/metrics/frame_sequence_tracker.h
@@ -182,12 +182,6 @@ termination_status_ = TerminationStatus::kScheduledForTermination; } - inline void LogFrameSequenceTrace(unsigned char letter) { -#if DCHECK_IS_ON() - frame_sequence_trace_.push_back(letter); -#endif - } - struct TrackedFrameData { // Represents the |BeginFrameArgs::source_id| and // |BeginFrameArgs::sequence_number| fields of the last processed @@ -292,15 +286,15 @@ const base::TimeDelta time_delta_to_report_ = base::TimeDelta::FromSeconds(5); #if DCHECK_IS_ON() - // This string represents a sequence of frame reporting activities on the - // current tracker. Each letter can be one of the following: + // This stringstream represents a sequence of frame reporting activities on + // the current tracker. Each letter can be one of the following: // {'B', 'N', 'b', 'n', 'S', 'P'}, where // 'B' = ReportBeginMainFrame(), 'N' = ReportMainFrameCausedNoDamage(), // 'b' = ReportBeginImplFrame(), 'n' = ReportMainFrameCausedNoDamage(), // 'S' = ReportSubmitFrame() and 'P' = ReportFramePresented(). // Note that |frame_sequence_trace_| is only defined and populated // when DCHECK is on. - std::string frame_sequence_trace_; + std::stringstream frame_sequence_trace_; #endif };
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni index 3285707..69ca95b 100644 --- a/chrome/android/chrome_test_java_sources.gni +++ b/chrome/android/chrome_test_java_sources.gni
@@ -125,6 +125,7 @@ "javatests/src/org/chromium/chrome/browser/customtabs/DetachedResourceRequestTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/RequestThrottlerTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/TrustedCdnPublisherUrlTest.java", + "javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleLoaderTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModuleNavigationTest.java", "javatests/src/org/chromium/chrome/browser/customtabs/dynamicmodule/CustomTabsDynamicModulePostMessageTest.java",
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java index b2a70219..9c7bb9f 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingMediator.java
@@ -74,8 +74,8 @@ */ class ManualFillingMediator extends EmptyTabObserver implements KeyboardAccessoryCoordinator.VisibilityDelegate, View.OnLayoutChangeListener { - static private final int MINIMAL_AVAILABLE_VERTICAL_SPACE = 128; // in DP. - static private final int MINIMAL_AVAILABLE_HORIZONTAL_SPACE = 180; // in DP. + private static final int MINIMAL_AVAILABLE_VERTICAL_SPACE = 128; // in DP. + private static final int MINIMAL_AVAILABLE_HORIZONTAL_SPACE = 180; // in DP. private PropertyModel mModel = ManualFillingProperties.createFillingModel(); private WindowAndroid mWindowAndroid;
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingState.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingState.java index 2594479..96c5323e 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingState.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/ManualFillingState.java
@@ -25,7 +25,7 @@ * and its sheet for the {@link WebContents} it is attached to. */ class ManualFillingState { - private final static int[] TAB_ORDER = { + private static final int[] TAB_ORDER = { AccessoryTabType.PASSWORDS, AccessoryTabType.CREDIT_CARDS, AccessoryTabType.ADDRESSES,
diff --git a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabCoordinator.java b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabCoordinator.java index 694be144..6004fb3 100644 --- a/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabCoordinator.java +++ b/chrome/android/features/keyboard_accessory/internal/java/src/org/chromium/chrome/browser/keyboard_accessory/sheet_tabs/AccessorySheetTabCoordinator.java
@@ -33,7 +33,7 @@ * Provides the icon used for a sheet. Simplifies mocking in controller tests. */ @VisibleForTesting - static public class IconProvider { + public static class IconProvider { private static Drawable sTestIcon; /**
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected index 41969be..fc9c4544 100644 --- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected +++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -1012,14 +1012,14 @@ android:launchMode="singleTop" android:name="org.chromium.android_webview.devui.CrashesListActivity" android:process=":webview_apk" - android:theme="@android:style/Theme.DeviceDefault"/> + android:theme="@style/Theme.DevUi.DayNight"/> <activity android:label="WebView DevTools" android:launchMode="singleTask" android:name="org.chromium.android_webview.devui.MainActivity" android:process=":webview_apk" - android:theme="@android:style/Theme.DeviceDefault"> + android:theme="@style/Theme.DevUi.DayNight"> <intent-filter> <action android:name="com.android.webview.SHOW_DEV_UI"/> <category android:name="android.intent.category.DEFAULT"/>
diff --git a/chrome/android/java/res/drawable-hdpi/overlay_side_shadow.9.png b/chrome/android/java/res/drawable-hdpi/overlay_side_shadow.9.png new file mode 100644 index 0000000..6d0b940 --- /dev/null +++ b/chrome/android/java/res/drawable-hdpi/overlay_side_shadow.9.png Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/overlay_side_shadow.9.png b/chrome/android/java/res/drawable-mdpi/overlay_side_shadow.9.png new file mode 100644 index 0000000..538d4e5c --- /dev/null +++ b/chrome/android/java/res/drawable-mdpi/overlay_side_shadow.9.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/overlay_side_shadow.9.png b/chrome/android/java/res/drawable-xhdpi/overlay_side_shadow.9.png new file mode 100644 index 0000000..104c1fa --- /dev/null +++ b/chrome/android/java/res/drawable-xhdpi/overlay_side_shadow.9.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/overlay_side_shadow.9.png b/chrome/android/java/res/drawable-xxhdpi/overlay_side_shadow.9.png new file mode 100644 index 0000000..f28c3454 --- /dev/null +++ b/chrome/android/java/res/drawable-xxhdpi/overlay_side_shadow.9.png Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/overlay_side_shadow.9.png b/chrome/android/java/res/drawable-xxxhdpi/overlay_side_shadow.9.png new file mode 100644 index 0000000..a227ed9 --- /dev/null +++ b/chrome/android/java/res/drawable-xxxhdpi/overlay_side_shadow.9.png Binary files differ
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java index 07886697..be66ac09 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
@@ -32,7 +32,7 @@ private final TabObserver mTabObserver = new EmptyTabObserver() { @Override public void onSSLStateUpdated(Tab tab) { - updateBrowserControlsState(tab); + updateBrowserControlsState(); } }; @@ -40,7 +40,7 @@ new CustomTabActivityTabProvider.Observer() { @Override public void onTabSwapped(@NonNull Tab tab) { - updateBrowserControlsState(tab); + updateBrowserControlsState(); } }; @@ -60,20 +60,20 @@ if (mInTwaMode == inTwaMode) return; mInTwaMode = inTwaMode; - updateBrowserControlsState(mTabProvider.getTab()); + updateBrowserControlsState(); if (mInTwaMode) { - mTabObserverRegistrar.registerTabObserver(mTabObserver); + mTabObserverRegistrar.registerActivityTabObserver(mTabObserver); mTabProvider.addObserver(mActivityTabObserver); } else { - mTabObserverRegistrar.unregisterTabObserver(mTabObserver); + mTabObserverRegistrar.unregisterActivityTabObserver(mTabObserver); mTabProvider.removeObserver(mActivityTabObserver); } } - private void updateBrowserControlsState(Tab tab) { + private void updateBrowserControlsState() { @BrowserControlsState - int newBrowserControlsState = computeBrowserControlsState(tab); + int newBrowserControlsState = computeBrowserControlsState(mTabProvider.getTab()); if (mBrowserControlsState == newBrowserControlsState) return; mBrowserControlsState = newBrowserControlsState;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java index a1312b6..740e73a2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -17,6 +17,7 @@ import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.compositor.LayerTitleCache; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager.PanelPriority; import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost; @@ -364,6 +365,12 @@ return mPanelShown; } + /** @return Whether we're using the new Overlay layout feature. */ + public static boolean isNewLayout() { + return ChromeFeatureList.isInitialized() + && ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT); + } + // ============================================================================================ // ActivityStateListener // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java index 3cfd637..21ee2d4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -16,7 +16,6 @@ import org.chromium.base.VisibleForTesting; import org.chromium.chrome.R; import org.chromium.chrome.browser.ChromeActivity; -import org.chromium.chrome.browser.ChromeFeatureList; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason; import org.chromium.chrome.browser.util.MathUtils; @@ -151,8 +150,8 @@ mProgressBarHeight = PROGRESS_BAR_HEIGHT_DP; mBarBorderHeight = BAR_BORDER_HEIGHT_DP; - int bar_height_dimen = isNewLayout() ? R.dimen.overlay_panel_bar_height - : R.dimen.overlay_panel_bar_height_legacy; + int bar_height_dimen = OverlayPanel.isNewLayout() ? R.dimen.overlay_panel_bar_height + : R.dimen.overlay_panel_bar_height_legacy; mBarHeight = mContext.getResources().getDimension(bar_height_dimen) * mPxToDp; final Resources resources = mContext.getResources(); @@ -164,7 +163,7 @@ mButtonPaddingDps = (int) (mPxToDp * resources.getDimension(R.dimen.overlay_panel_button_padding)); mBarShadowVisible = true; - mPanelShadowVisible = !isNewLayout(); + mPanelShadowVisible = true; } // ============================================================================================ @@ -355,12 +354,6 @@ return Math.round(mMaximumHeight / mPxToDp); } - /** @return Whether we're using the new Overlay layout feature. */ - private boolean isNewLayout() { - return ChromeFeatureList.isInitialized() - && ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT); - } - /** @return The offset for the page content in DPs. */ protected float getLayoutOffsetYDps() { return mLayoutYOffset * mPxToDp; @@ -513,7 +506,7 @@ * @return The opacity of the arrow icon. */ public float getArrowIconOpacity() { - return isNewLayout() ? ARROW_ICON_OPACITY_TRANSPARENT : mArrowIconOpacity; + return OverlayPanel.isNewLayout() ? ARROW_ICON_OPACITY_TRANSPARENT : mArrowIconOpacity; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java index 97fab76..b86f0aa 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabBarControl.java
@@ -8,6 +8,7 @@ import android.view.ViewGroup; import org.chromium.chrome.R; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; /** @@ -36,7 +37,7 @@ public EphemeralTabBarControl(EphemeralTabPanel panel, Context context, ViewGroup container, DynamicResourceLoader loader) { mTitle = new EphemeralTabTitleControl(panel, context, container, loader); - mCaption = EphemeralTabPanel.isNewLayout() || panel.canPromoteToNewTab() + mCaption = OverlayPanel.isNewLayout() || panel.canPromoteToNewTab() ? new EphemeralTabCaptionControl(panel, context, container, loader) : null; mTextLayerMinHeight = @@ -65,7 +66,7 @@ * @param percentage The percentage to the more opened state. */ public void updateForCloseOrPeek(float percentage) { - if (EphemeralTabPanel.isNewLayout()) { + if (OverlayPanel.isNewLayout()) { updateForMaximize(SOLID_OPAQUE); } else { if (percentage == SOLID_OPAQUE) updateForMaximize(SOLID_TRANSPARENT);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java index bee7048..0d210a1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabCaptionControl.java
@@ -14,6 +14,7 @@ import org.chromium.base.Supplier; import org.chromium.chrome.R; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelTextViewInflater; import org.chromium.components.url_formatter.UrlFormatter; import org.chromium.ui.resources.dynamics.DynamicResourceLoader; @@ -56,10 +57,10 @@ DynamicResourceLoader resourceLoader) { super(panel, R.layout.ephemeral_tab_caption_view, R.id.ephemeral_tab_caption_view, context, container, resourceLoader, - (EphemeralTabPanel.isNewLayout() ? R.dimen.overlay_panel_end_buttons_width - : R.dimen.overlay_panel_padded_button_width), - (EphemeralTabPanel.isNewLayout() ? R.dimen.overlay_panel_end_buttons_width - : R.dimen.overlay_panel_padded_button_width)); + (OverlayPanel.isNewLayout() ? R.dimen.overlay_panel_end_buttons_width + : R.dimen.overlay_panel_padded_button_width), + (OverlayPanel.isNewLayout() ? R.dimen.overlay_panel_end_buttons_width + : R.dimen.overlay_panel_padded_button_width)); mUrl = panel::getUrl; mIconMargin = context.getResources().getDimensionPixelSize( R.dimen.preview_tab_security_icon_size); @@ -77,7 +78,7 @@ if (mCaption == null) { // |mCaption| gets initialized synchronously in |onFinishInflate|. inflate(); - if (EphemeralTabPanel.isNewLayout()) { + if (OverlayPanel.isNewLayout()) { mCaption.setText( UrlFormatter.formatUrlForSecurityDisplayOmitScheme(mUrl.get())); } else { @@ -139,7 +140,7 @@ * @return The current percentage ranging from 0.0 to 1.0. */ public float getAnimationPercentage() { - return EphemeralTabPanel.isNewLayout() ? 1.f : mAnimationPercentage; + return OverlayPanel.isNewLayout() ? 1.f : mAnimationPercentage; } /** @@ -167,7 +168,7 @@ View view = getView(); mCaption = (TextView) view.findViewById(R.id.ephemeral_tab_caption); - if (EphemeralTabPanel.isNewLayout()) { + if (OverlayPanel.isNewLayout()) { ((MarginLayoutParams) mCaption.getLayoutParams()).leftMargin = mIconMargin; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java index 2bf5ba7..a1a97db 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/ephemeraltab/EphemeralTabPanel.java
@@ -97,10 +97,6 @@ && !SysUtils.isLowEndDevice(); } - static boolean isNewLayout() { - return ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT); - } - /** * @param context The current Android {@link Context}. * @param updateHost The {@link LayoutUpdateHost} used to request updates in the Layout.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java index 9efc7ac6..5a1ac80 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java
@@ -8,7 +8,7 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchBarBannerControl; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchBarControl; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchImageControl; @@ -65,13 +65,11 @@ int searchTermViewId = searchBarControl.getSearchTermViewId(); int searchCaptionViewId = searchBarControl.getCaptionViewId(); - int openNewTabIconId = (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) - && panel.canPromoteToNewTab()) + int openNewTabIconId = OverlayPanel.isNewLayout() && panel.canPromoteToNewTab() ? R.drawable.open_in_new_tab : INVALID_RESOURCE_ID; - int dragHandlebarId = ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) - ? R.drawable.drag_handlebar - : INVALID_RESOURCE_ID; + int dragHandlebarId = + OverlayPanel.isNewLayout() ? R.drawable.drag_handlebar : INVALID_RESOURCE_ID; int searchPromoViewId = promoControl.getViewId(); boolean searchPromoVisible = promoControl.isVisible(); @@ -143,14 +141,16 @@ WebContents panelWebContents = panel.getWebContents(); int roundedBarTopResourceId = - ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) - ? R.drawable.top_round - : INVALID_RESOURCE_ID; + OverlayPanel.isNewLayout() ? R.drawable.top_round : INVALID_RESOURCE_ID; int separatorLineColor = panel.getSeparatorLineColor(); + // The panel shadow goes all the way around in the old layout, but in the new layout + // the top_round resource also includes the shadow so we only need a side shadow. + // In either case there's just one shadow-only resource needed. int panelShadowResourceId = panel.getPanelShadowVisible() - ? R.drawable.contextual_search_bar_background + ? (OverlayPanel.isNewLayout() ? R.drawable.overlay_side_shadow + : R.drawable.contextual_search_bar_background) : INVALID_RESOURCE_ID; - int closeIconResourceId = ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) + int closeIconResourceId = OverlayPanel.isNewLayout() ? INVALID_RESOURCE_ID : ContextualSearchPanel.CLOSE_ICON_DRAWABLE_ID;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java index 1c31ef8..780714b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/EphemeralTabSceneLayer.java
@@ -10,7 +10,7 @@ import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; import org.chromium.chrome.R; -import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabBarControl; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabCaptionControl; import org.chromium.chrome.browser.compositor.bottombar.ephemeraltab.EphemeralTabPanel; @@ -70,18 +70,19 @@ EphemeralTabSceneLayerJni.get().createEphemeralTabLayer(mNativePtr, EphemeralTabSceneLayer.this, resourceManager, () -> panel.startFaviconAnimation(true)); - int openInTabIconId = (ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) - && panel.canPromoteToNewTab()) + int openInTabIconId = (OverlayPanel.isNewLayout() && panel.canPromoteToNewTab()) ? R.drawable.open_in_new_tab : INVALID_RESOURCE_ID; - int dragHandlebarId = ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) - ? R.drawable.drag_handlebar - : INVALID_RESOURCE_ID; - int roundedBarTopId = ChromeFeatureList.isEnabled(ChromeFeatureList.OVERLAY_NEW_LAYOUT) - ? R.drawable.top_round - : INVALID_RESOURCE_ID; + int dragHandlebarId = + OverlayPanel.isNewLayout() ? R.drawable.drag_handlebar : INVALID_RESOURCE_ID; + int roundedBarTopId = + OverlayPanel.isNewLayout() ? R.drawable.top_round : INVALID_RESOURCE_ID; + // The panel shadow goes all the way around in the old layout, but in the new layout + // the top_round resource also includes the shadow so we only need a side shadow. + // In either case there's just one shadow-only resource needed. int panelShadowResourceId = panel.getPanelShadowVisible() - ? R.drawable.contextual_search_bar_background + ? (OverlayPanel.isNewLayout() ? R.drawable.overlay_side_shadow + : R.drawable.contextual_search_bar_background) : INVALID_RESOURCE_ID; EphemeralTabSceneLayerJni.get().setResourceIds(mNativePtr, EphemeralTabSceneLayer.this, title.getViewId(), panelShadowResourceId, roundedBarTopId,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInteractionPersisterImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInteractionPersisterImpl.java index e0ea35b..1f14f19 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInteractionPersisterImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchInteractionPersisterImpl.java
@@ -7,7 +7,7 @@ import androidx.annotation.Nullable; import org.chromium.chrome.browser.contextualsearch.ContextualSearchInteractionRecorder.Feature; -import org.chromium.chrome.browser.preferences.ChromePreferenceManager; +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import java.util.Map; @@ -71,40 +71,38 @@ /** @param eventId An event ID to write to local storage. */ private void writeEventIDToPersistantStorage(long eventId) { SharedPreferencesManager.getInstance().writeLong( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID, eventId); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID, eventId); } /** @return The event ID from local storage. */ private long readEventIdFromPersistantStorage() { return SharedPreferencesManager.getInstance().readLong( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID, - NO_EVENT_ID); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID, NO_EVENT_ID); } /** @param bitEncodedValue An encoded outcome to write to local storage. */ private void writeOutcomesToPersistantStorage(int bitEncodedValue) { SharedPreferencesManager.getInstance().writeInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES, + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES, bitEncodedValue); } /** @return The encoded outcome from local storage. */ private int readOutcomesFromPersistantStorage() { return SharedPreferencesManager.getInstance().readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES); } /** Writes the current time stamp to local storage. */ private void writeTimestampToPersistantStorage(long timestamp) { SharedPreferencesManager.getInstance().writeLong( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP, - timestamp); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP, timestamp); } /** @return The time stamp when we wrote the outcome to local storage. */ private long readTimestampFromPersistantStorage() { return SharedPreferencesManager.getInstance().readLong( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP, 0); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP, 0); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java index a72e321a..c1ec9b5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -20,7 +20,7 @@ import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial.ContextualSearchSetting; import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial.ContextualSearchSwitch; import org.chromium.chrome.browser.contextualsearch.ContextualSearchSelectionController.SelectionType; -import org.chromium.chrome.browser.preferences.ChromePreferenceManager; +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.PrefServiceBridge; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; import org.chromium.chrome.browser.util.UrlConstants; @@ -197,14 +197,13 @@ if (promoTapCounter.isEnabled()) promoTapCounter.increment(); } int tapsSinceOpen = mPreferencesManager.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT); if (isUserUndecided()) { ContextualSearchUma.logTapsSinceOpenForUndecided(tapsSinceOpen); } else { ContextualSearchUma.logTapsSinceOpenForDecided(tapsSinceOpen); } - mPreferencesManager.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ALL_TIME_TAP_COUNT); + mPreferencesManager.incrementInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_ALL_TIME_TAP_COUNT); } /** @@ -213,9 +212,9 @@ void updateCountersForOpen() { // Always completely reset the tap counters that accumulate only since the last open. mPreferencesManager.writeInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT, 0); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT, 0); mPreferencesManager.writeInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_QUICK_ANSWER_COUNT, 0); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_QUICK_ANSWER_COUNT, 0); // Disable the "promo tap" counter, but only if we're using the Opt-out onboarding. // For Opt-in, we never disable the promo tap counter. @@ -224,11 +223,11 @@ // Bump the total-promo-opens counter. int count = mPreferencesManager.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT); ContextualSearchUma.logPromoOpenCount(count); } mPreferencesManager.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ALL_TIME_OPEN_COUNT); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ALL_TIME_OPEN_COUNT); } /** @@ -240,9 +239,9 @@ void updateCountersForQuickAnswer(boolean wasActivatedByTap, boolean doesAnswer) { if (wasActivatedByTap && doesAnswer) { mPreferencesManager.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_QUICK_ANSWER_COUNT); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_QUICK_ANSWER_COUNT); mPreferencesManager.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ALL_TIME_TAP_QUICK_ANSWER_COUNT); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ALL_TIME_TAP_QUICK_ANSWER_COUNT); } } @@ -343,10 +342,10 @@ if (selectionType == SelectionType.TAP) { long currentTimeMillis = System.currentTimeMillis(); long lastAnimatedTimeMillis = mPreferencesManager.readLong( - ChromePreferenceManager.CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME); if (Math.abs(currentTimeMillis - lastAnimatedTimeMillis) > DateUtils.DAY_IN_MILLIS) { mPreferencesManager.writeLong( - ChromePreferenceManager.CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME, + ChromePreferenceKeys.CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME, currentTimeMillis); return true; } else { @@ -391,8 +390,7 @@ */ @VisibleForTesting int getPromoOpenCount() { - return mPreferencesManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT); + return mPreferencesManager.readInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT); } /** @@ -401,7 +399,7 @@ @VisibleForTesting int getTapCount() { return mPreferencesManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT); } // --------------------------------------------------------------------------------------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java index f5c857d2..c64b2e6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRankerLoggerImpl.java
@@ -62,9 +62,10 @@ public ContextualSearchRankerLoggerImpl( ContextualSearchInteractionPersister interactionPersister) { mInteractionPersister = interactionPersister; - if (isEnabled()) + if (isEnabled()) { mNativePointer = ContextualSearchRankerLoggerImplJni.get().init( ContextualSearchRankerLoggerImpl.this); + } } /** @@ -74,7 +75,7 @@ * not. */ @VisibleForTesting - protected final static String outcomeName(@Feature int feature) { + protected static final String outcomeName(@Feature int feature) { switch (feature) { case Feature.OUTCOME_WAS_PANEL_OPENED: return "OutcomeWasPanelOpened"; @@ -97,7 +98,7 @@ * expected to be logged. */ @VisibleForTesting - protected final static String featureName(@Feature int feature) { + protected static final String featureName(@Feature int feature) { // NOTE: this list needs to be kept in sync with the white list in // predictor_config_definitions.cc and with ukm.xml! switch (feature) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/CtrSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/CtrSuppression.java index b866b4f..447e094 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/CtrSuppression.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/CtrSuppression.java
@@ -6,7 +6,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.NativeMethods; -import org.chromium.chrome.browser.preferences.ChromePreferenceManager; +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; /** @@ -149,14 +149,12 @@ * or we have never checked. */ private boolean didWeekChange(int currentWeekNumber) { - if (mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER) + if (mPreferenceManager.readInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER) == currentWeekNumber) { return false; } else { mPreferenceManager.writeInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER, - currentWeekNumber); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER, currentWeekNumber); return true; } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/DisableablePromoTapCounter.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/DisableablePromoTapCounter.java index bcb7c45..c9a5876 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/DisableablePromoTapCounter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/DisableablePromoTapCounter.java
@@ -5,7 +5,7 @@ package org.chromium.chrome.browser.contextualsearch; import org.chromium.base.VisibleForTesting; -import org.chromium.chrome.browser.preferences.ChromePreferenceManager; +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; /** @@ -52,7 +52,7 @@ private DisableablePromoTapCounter(SharedPreferencesManager prefsManager) { mPrefsManager = prefsManager; setRawCounter(prefsManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT)); } /** @@ -108,7 +108,7 @@ */ private void writeRawCounter() { mPrefsManager.writeInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT, mCounter); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT, mCounter); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/EngagementSuppression.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/EngagementSuppression.java index 297c2e62..f4e33231 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/EngagementSuppression.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/EngagementSuppression.java
@@ -5,7 +5,7 @@ package org.chromium.chrome.browser.contextualsearch; import org.chromium.chrome.browser.contextualsearch.ContextualSearchFieldTrial.ContextualSearchSwitch; -import org.chromium.chrome.browser.preferences.ChromePreferenceManager; +import org.chromium.chrome.browser.preferences.ChromePreferenceKeys; import org.chromium.chrome.browser.preferences.SharedPreferencesManager; /** @@ -27,23 +27,22 @@ // OR had a Quick Action presented but none taken and at least one ignored. boolean hadEntityImpression = mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT) + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT) > 0; - boolean hadEntityOpen = - mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT) + boolean hadEntityOpen = mPreferenceManager.readInt( + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT) > 0; boolean hadQuickActionImpression = mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT) + ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT) > 0; boolean hadQuickActionTaken = mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT) + ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT) > 0; boolean hadQuickActionIgnored = mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT) + ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT) > 0; mIsConditionSatisfied = (hadEntityImpression && !hadEntityOpen) || (hadQuickActionImpression && !hadQuickActionTaken && hadQuickActionIgnored); @@ -58,13 +57,11 @@ public static void registerQuickActionImpression( boolean wasPanelOpened, boolean wasActionClicked) { SharedPreferencesManager prefs = SharedPreferencesManager.getInstance(); - prefs.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT); + prefs.incrementInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT); if (wasActionClicked) { - prefs.incrementInt(ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT); + prefs.incrementInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT); } else if (wasPanelOpened) { - prefs.incrementInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT); + prefs.incrementInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT); } } @@ -75,9 +72,9 @@ */ public static void registerContextualCardsImpression(boolean wasPanelOpened) { SharedPreferencesManager prefs = SharedPreferencesManager.getInstance(); - prefs.incrementInt(ChromePreferenceManager.CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT); + prefs.incrementInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT); if (wasPanelOpened) { - prefs.incrementInt(ChromePreferenceManager.CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT); + prefs.incrementInt(ChromePreferenceKeys.CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT); } } @@ -95,29 +92,29 @@ // These counters are updated in ContextualSearchPolcy when taps and opens are registered. logger.logFeature(ContextualSearchInteractionRecorder.Feature.TAP_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ALL_TIME_TAP_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ALL_TIME_TAP_COUNT)); logger.logFeature(ContextualSearchInteractionRecorder.Feature.OPEN_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ALL_TIME_OPEN_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ALL_TIME_OPEN_COUNT)); logger.logFeature(ContextualSearchInteractionRecorder.Feature.QUICK_ANSWER_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ALL_TIME_TAP_QUICK_ANSWER_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ALL_TIME_TAP_QUICK_ANSWER_COUNT)); // These counters are updated in the #registerX static methods of this class. logger.logFeature(ContextualSearchInteractionRecorder.Feature.ENTITY_IMPRESSIONS_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT)); logger.logFeature(ContextualSearchInteractionRecorder.Feature.ENTITY_OPENS_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT)); logger.logFeature( ContextualSearchInteractionRecorder.Feature.QUICK_ACTION_IMPRESSIONS_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT)); logger.logFeature(ContextualSearchInteractionRecorder.Feature.QUICK_ACTIONS_TAKEN_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT)); logger.logFeature(ContextualSearchInteractionRecorder.Feature.QUICK_ACTIONS_IGNORED_COUNT, mPreferenceManager.readInt( - ChromePreferenceManager.CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT)); + ChromePreferenceKeys.CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT)); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java index 05029b2..6bc6b18 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrar.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.customtabs.content; +import androidx.annotation.NonNull; + import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; import org.chromium.chrome.browser.lifecycle.Destroyable; @@ -25,9 +27,37 @@ */ @ActivityScope public class TabObserverRegistrar extends EmptyTabModelObserver implements Destroyable { + private CustomTabActivityTabProvider mTabProvider; private final Set<PageLoadMetrics.Observer> mPageLoadMetricsObservers = new HashSet<>(); private final Set<TabObserver> mTabObservers = new HashSet<>(); + /** Observers for active tab. */ + private final Set<TabObserver> mActivityTabObservers = new HashSet<>(); + + /** + * Caches the {@link CustomTabActivityTabProvider}'s active tab so that TabObservers can be + * removed from the previous active tab when the active tab changes. + */ + private Tab mTabProviderTab; + + private final CustomTabActivityTabProvider.Observer mActivityTabProviderObserver = + new CustomTabActivityTabProvider.Observer() { + @Override + public void onInitialTabCreated(@NonNull Tab tab, @TabCreationMode int mode) { + onTabProviderTabUpdated(); + } + + @Override + public void onTabSwapped(@NonNull Tab tab) { + onTabProviderTabUpdated(); + } + + @Override + public void onAllTabsClosed() { + onTabProviderTabUpdated(); + } + }; + /** * Registers a {@link PageLoadMetrics.Observer} to be managed by this Registrar. */ @@ -49,8 +79,33 @@ mTabObservers.remove(observer); } + /** + * Registers a TabObserver for the CustomTabActivity's active tab. Changes the Tab that is + * being observed when the CustomTabActivity's active tab changes. + * Differs from {@link #registerTabObserver()} which observes all newly created tabs. + */ + public void registerActivityTabObserver(TabObserver observer) { + mActivityTabObservers.add(observer); + Tab activeTab = mTabProvider.getTab(); + if (activeTab != null) { + activeTab.addObserver(observer); + } + } + + public void unregisterActivityTabObserver(TabObserver observer) { + mActivityTabObservers.remove(observer); + Tab activeTab = mTabProvider.getTab(); + if (activeTab != null) { + activeTab.removeObserver(observer); + } + } + @Inject - public TabObserverRegistrar(ActivityLifecycleDispatcher lifecycleDispatcher) { + public TabObserverRegistrar(ActivityLifecycleDispatcher lifecycleDispatcher, + CustomTabActivityTabProvider tabProvider) { + mTabProvider = tabProvider; + mTabProvider.addObserver(mActivityTabProviderObserver); + lifecycleDispatcher.register(this); } @@ -69,7 +124,7 @@ @Override public void tabRemoved(Tab tab) { removePageLoadMetricsObservers(); - removeTabObservers(tab); + removeTabObservers(tab, mTabObservers); } /** @@ -78,7 +133,7 @@ */ public void addObserversForTab(Tab tab) { addPageLoadMetricsObservers(); - addTabObservers(tab); + addTabObservers(tab, mTabObservers); } private void addPageLoadMetricsObservers() { @@ -93,14 +148,27 @@ } } - private void addTabObservers(Tab tab) { - for (TabObserver observer : mTabObservers) { + /** + * Called when the {@link CustomTabActivityTabProvider}'s active tab has changed. + */ + private void onTabProviderTabUpdated() { + if (mTabProviderTab != null) { + removeTabObservers(mTabProviderTab, mActivityTabObservers); + } + mTabProviderTab = mTabProvider.getTab(); + if (mTabProviderTab != null) { + addTabObservers(mTabProviderTab, mActivityTabObservers); + } + } + + private void addTabObservers(Tab tab, Set<TabObserver> tabObservers) { + for (TabObserver observer : tabObservers) { tab.addObserver(observer); } } - private void removeTabObservers(Tab tab) { - for (TabObserver observer : mTabObservers) { + private void removeTabObservers(Tab tab, Set<TabObserver> tabObservers) { + for (TabObserver observer : tabObservers) { tab.removeObserver(observer); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java index cdfe253..36ff57e4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dependency_injection/CustomTabActivityComponent.java
@@ -20,6 +20,7 @@ import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabFactory; import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider; import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler; +import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar; import org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleCoordinator; import org.chromium.chrome.browser.customtabs.dynamicmodule.DynamicModuleToolbarController; import org.chromium.chrome.browser.customtabs.features.ImmersiveModeController; @@ -56,6 +57,7 @@ CustomTabCompositorContentInitializer resolveCompositorContentInitializer(); CustomTabSessionHandler resolveSessionHandler(); CustomTabActivityClientConnectionKeeper resolveConnectionKeeper(); + TabObserverRegistrar resolveTabObserverRegistrar(); TwaFinishHandler resolveTwaFinishHandler(); ImmersiveModeController resolveImmersiveModeController();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java index ff8c798..7165391a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
@@ -4,8 +4,11 @@ package org.chromium.chrome.browser.customtabs.features.toolbar; +import androidx.annotation.NonNull; + import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider; +import org.chromium.chrome.browser.customtabs.content.CustomTabActivityTabProvider; import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar; import org.chromium.chrome.browser.dependency_injection.ActivityScope; import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher; @@ -28,16 +31,33 @@ private final BrowserServicesIntentDataProvider mIntentDataProvider; private final ChromeActivity mActivity; private final TabObserverRegistrar mTabObserverRegistrar; + private final CustomTabActivityTabProvider mTabProvider; + + /** Keeps track of the original color before the preview was shown. */ + private int mOriginalColor; + + /** True if a change to the toolbar color was made because of a preview. */ + private boolean mTriggeredPreviewChange; + + private final CustomTabActivityTabProvider.Observer mActivityTabObserver = + new CustomTabActivityTabProvider.Observer() { + @Override + public void onTabSwapped(@NonNull Tab tab) { + updateColor(tab); + } + }; @Inject public CustomTabToolbarColorController(ActivityLifecycleDispatcher lifecycleDispatcher, Lazy<ToolbarManager> toolbarManager, BrowserServicesIntentDataProvider intentDataProvider, ChromeActivity activity, + CustomTabActivityTabProvider tabProvider, TabObserverRegistrar tabObserverRegistrar) { mToolbarManager = toolbarManager; mIntentDataProvider = intentDataProvider; mActivity = activity; + mTabProvider = tabProvider; mTabObserverRegistrar = tabObserverRegistrar; lifecycleDispatcher.register(this); } @@ -56,16 +76,11 @@ manager.setShouldUpdateToolbarPrimaryColor(false); } observeTabToUpdateColor(); + mTabProvider.addObserver(mActivityTabObserver); } private void observeTabToUpdateColor() { - mTabObserverRegistrar.registerTabObserver(new EmptyTabObserver() { - /** Keeps track of the original color before the preview was shown. */ - private int mOriginalColor; - - /** True if a change to the toolbar color was made because of a preview. */ - private boolean mTriggeredPreviewChange; - + mTabObserverRegistrar.registerActivityTabObserver(new EmptyTabObserver() { @Override public void onPageLoadFinished(Tab tab, String url) { // Update the color when the page load finishes. @@ -77,37 +92,37 @@ // Update the color on every new URL. updateColor(tab); } - - /** - * Updates the color of the Activity's CCT Toolbar. When a preview is shown, it should - * be reset to the default color. If the user later navigates away from that preview to - * a non-preview page, reset the color back to the original. This does not interfere - * with site-specific theme colors which are disabled when a preview is being shown. - */ - private void updateColor(Tab tab) { - ToolbarManager manager = mToolbarManager.get(); - - // Record the original toolbar color in case we need to revert back to it later - // after a preview has been shown then the user navigates to another non-preview - // page. - if (mOriginalColor == 0) mOriginalColor = manager.getPrimaryColor(); - - final boolean shouldUpdateOriginal = manager.getShouldUpdateToolbarPrimaryColor(); - manager.setShouldUpdateToolbarPrimaryColor(true); - - if (tab.isPreview()) { - final int defaultColor = - ChromeColors.getDefaultThemeColor(mActivity.getResources(), false); - manager.onThemeColorChanged(defaultColor, false); - mTriggeredPreviewChange = true; - } else if (mOriginalColor != manager.getPrimaryColor() && mTriggeredPreviewChange) { - manager.onThemeColorChanged(mOriginalColor, false); - mTriggeredPreviewChange = false; - mOriginalColor = 0; - } - - manager.setShouldUpdateToolbarPrimaryColor(shouldUpdateOriginal); - } }); } + + /** + * Updates the color of the Activity's CCT Toolbar. When a preview is shown, it should + * be reset to the default color. If the user later navigates away from that preview to + * a non-preview page, reset the color back to the original. This does not interfere + * with site-specific theme colors which are disabled when a preview is being shown. + */ + private void updateColor(Tab tab) { + ToolbarManager manager = mToolbarManager.get(); + + // Record the original toolbar color in case we need to revert back to it later + // after a preview has been shown then the user navigates to another non-preview + // page. + if (mOriginalColor == 0) mOriginalColor = manager.getPrimaryColor(); + + final boolean shouldUpdateOriginal = manager.getShouldUpdateToolbarPrimaryColor(); + manager.setShouldUpdateToolbarPrimaryColor(true); + + if (tab.isPreview()) { + final int defaultColor = + ChromeColors.getDefaultThemeColor(mActivity.getResources(), false); + manager.onThemeColorChanged(defaultColor, false); + mTriggeredPreviewChange = true; + } else if (mOriginalColor != manager.getPrimaryColor() && mTriggeredPreviewChange) { + manager.onThemeColorChanged(mOriginalColor, false); + mTriggeredPreviewChange = false; + mOriginalColor = 0; + } + + manager.setShouldUpdateToolbarPrimaryColor(shouldUpdateOriginal); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameUtils.java index fd234d1..2ce252b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/rename/RenameUtils.java
@@ -11,7 +11,7 @@ * A class containing some utility static methods for rename. */ public class RenameUtils { - static private boolean sIsDisabledNativeForTesting; + private static boolean sIsDisabledNativeForTesting; /** * Determine the extension of a downloaded item.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java index 1dffa8c..bff5d25a4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -68,7 +68,7 @@ * Returns whether prefetched suggestions metrics should be reported for a given category. * @param category given category to check. */ - static public boolean shouldReportPrefetchedSuggestionsMetrics(@CategoryInt int category) { + public static boolean shouldReportPrefetchedSuggestionsMetrics(@CategoryInt int category) { return category == KnownCategories.ARTICLES && !NetworkChangeNotifier.isOnline(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java index a3380d6..6b51d56 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarPhone.java
@@ -78,10 +78,10 @@ // children this way doesn't affect the views' bounds (including hit rect). But these // hit rects are preserved for the views that matter (the icon and the url actions // container). - int lateral_padding = getResources().getDimensionPixelOffset( + int lateralPadding = getResources().getDimensionPixelOffset( R.dimen.sei_location_bar_lateral_padding); - setPaddingRelative( - lateral_padding, getPaddingTop(), lateral_padding, getPaddingBottom()); + setPaddingRelative(lateralPadding, getPaddingTop(), lateralPadding, getPaddingBottom()); + updateUrlBarPaddingForSearchEngineIcon(); } // This branch will be hit if the search engine logo experiment is enabled and we should @@ -107,10 +107,12 @@ private void updateUrlBarPaddingForSearchEngineIcon() { if (mUrlBar == null || mStatusView == null) return; + // TODO(crbug.com/1019019): Come up with a better solution for M80 or M81. int endPadding = 0; - if (SearchEngineLogoUtils.shouldShowSearchEngineLogo(mToolbarDataProvider.isIncognito())) { + if (SearchEngineLogoUtils.shouldShowSearchEngineLogo(mToolbarDataProvider.isIncognito()) + && hasFocus()) { // This padding prevents the UrlBar's content from extending past the available space - // and into the next view. + // and into the next view while focused. endPadding = mStatusView.getEndPaddingPixelSizeForFocusState(true) - mStatusView.getEndPaddingPixelSizeForFocusState(false); } @@ -239,6 +241,7 @@ setFocusable(false); setFocusableInTouchMode(false); } + updateUrlBarPaddingForSearchEngineIcon(); setUrlFocusChangeInProgress(true); updateShouldAnimateIconChanges(); super.onUrlFocusChange(hasFocus); @@ -292,6 +295,7 @@ setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, false); getWindowAndroid().getKeyboardDelegate().showKeyboard(mUrlBar); } + updateUrlBarPaddingForSearchEngineIcon(); mStatusViewCoordinator.onUrlAnimationFinished(hasFocus); setUrlFocusChangeInProgress(false); updateShouldAnimateIconChanges();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java index af82827..4e9a8e8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/suggestions/basic/BasicSuggestionProcessor.java
@@ -170,7 +170,12 @@ model.get(SuggestionCommonProperties.USE_DARK_COLORS) ? R.color.suggestion_url_dark_modern : R.color.suggestion_url_light_modern); - textLine2Direction = View.TEXT_DIRECTION_LTR; + + if (suggestionType == OmniboxSuggestionType.CLIPBOARD_TEXT) { + textLine2Direction = View.TEXT_DIRECTION_INHERIT; + } else { + textLine2Direction = View.TEXT_DIRECTION_LTR; + } } else { textLine2 = null; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java index 5b0f8f8..cf42341b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/photo_picker/DecoderServiceHost.java
@@ -332,10 +332,11 @@ @DecodeVideoTask.DecodingResult int decodingResult) { switch (decodingResult) { case DecodeVideoTask.DecodingResult.SUCCESS: - if (bitmaps == null || bitmaps.size() == 0) + if (bitmaps == null || bitmaps.size() == 0) { mFailedVideoDecodesUnknown++; - else + } else { mSuccessfulVideoDecodes++; + } break; case DecodeVideoTask.DecodingResult.FILE_ERROR: mFailedVideoDecodesFile++;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java index 26ac805d..ca5cd42 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceManager.java
@@ -12,6 +12,8 @@ /** * ChromePreferenceManager stores and retrieves various values in Android shared preferences. + * + * TODO(crbug.com/1022107): Finish moving constants to ChromePreferenceKeys. */ public class ChromePreferenceManager { // For new int values with a default of 0, just document the key and its usage, and call @@ -19,82 +21,6 @@ // For new boolean values, document the key and its usage, call #readBoolean and #writeBoolean // directly. While calling #readBoolean, default value is required. - /** An all-time counter of taps that triggered the Contextual Search peeking panel. */ - public static final String CONTEXTUAL_SEARCH_ALL_TIME_TAP_COUNT = - "contextual_search_all_time_tap_count"; - /** An all-time counter of Contextual Search panel opens triggered by any gesture.*/ - public static final String CONTEXTUAL_SEARCH_ALL_TIME_OPEN_COUNT = - "contextual_search_all_time_open_count"; - /** - * The number of times a tap gesture caused a Contextual Search Quick Answer to be shown. - * Cumulative, starting at M-69. - */ - public static final String CONTEXTUAL_SEARCH_ALL_TIME_TAP_QUICK_ANSWER_COUNT = - "contextual_search_all_time_tap_quick_answer_count"; - /** - * The number of times that a tap triggered the Contextual Search panel to peek since the last - * time the panel was opened. Note legacy string value without "open". - */ - public static final String CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT = - "contextual_search_tap_count"; - /** - * The number of times a tap gesture caused a Contextual Search Quick Answer to be shown since - * the last time the panel was opened. Note legacy string value without "open". - */ - public static final String CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_QUICK_ANSWER_COUNT = - "contextual_search_tap_quick_answer_count"; - /** - * The number of times the Contextual Search panel was opened with the opt-in promo visible. - */ - public static final String CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT = - "contextual_search_promo_open_count"; - /** - * The entity-data impressions count for Contextual Search, i.e. thumbnails shown in the Bar. - * Cumulative, starting at M-69. - */ - public static final String CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT = - "contextual_search_entity_impressions_count"; - /** - * The entity-data opens count for Contextual Search, e.g. Panel opens following thumbnails - * shown in the Bar. Cumulative, starting at M-69. - */ - public static final String CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT = - "contextual_search_entity_opens_count"; - /** - * The Quick Action impressions count for Contextual Search, i.e. actions presented in the Bar. - * Cumulative, starting at M-69. - */ - public static final String CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT = - "contextual_search_quick_action_impressions_count"; - /** - * The Quick Actions taken count for Contextual Search, i.e. phone numbers dialed and similar - * actions. Cumulative, starting at M-69. - */ - public static final String CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT = - "contextual_search_quick_actions_taken_count"; - /** - * The Quick Actions ignored count, i.e. phone numbers available but not dialed. - * Cumulative, starting at M-69. - */ - public static final String CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT = - "contextual_search_quick_actions_ignored_count"; - /** - * A user interaction event ID for interaction with Contextual Search, stored as a long. - */ - public static final String CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID = - "contextual_search_previous_interaction_event_id"; - /** - * An encoded set of outcomes of user interaction with Contextual Search, stored as an int. - */ - public static final String CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES = - "contextual_search_previous_interaction_encoded_outcomes"; - /** - * A timestamp indicating when we updated the user interaction with Contextual Search, stored - * as a long, with resolution in days. - */ - public static final String CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP = - "contextual_search_previous_interaction_timestamp"; - /** * Whether the promotion for data reduction has been skipped on first invocation. * Default value is false. @@ -117,13 +43,6 @@ @Deprecated private static final String PREF_WEBSITE_SETTINGS_FILTER = "website_settings_filter"; - public static final String CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT = - "contextual_search_tap_triggered_promo_count"; - public static final String CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME = - "contextual_search_last_animation_time"; - public static final String CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER = - "contextual_search_current_week_number"; - /** * Whether Chrome is set as the default browser. * Default value is false.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java index 283650f..f03908c7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
@@ -258,8 +258,9 @@ if (AccessibilityUtil.isAccessibilityEnabled()) { durationMs *= 2; - if (durationMs < sAccessibilitySnackbarDurationMs) + if (durationMs < sAccessibilitySnackbarDurationMs) { durationMs = sAccessibilitySnackbarDurationMs; + } } return durationMs;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationManager.java b/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationManager.java index 885b52f..561f32a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/tracing/TracingNotificationManager.java
@@ -109,8 +109,9 @@ // selecting the stop button, so choose a different message. AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); - if (am.isEnabled() && am.isTouchExplorationEnabled()) + if (am.isEnabled() && am.isTouchExplorationEnabled()) { message = MSG_ACTIVE_NOTIFICATION_ACCESSIBILITY_MESSAGE; + } sTracingActiveNotificationBuilder = createNotificationBuilder()
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProvider.java index 1fb2fa06..bda27e2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebApkIntentDataProvider.java
@@ -227,6 +227,16 @@ int primaryMaskableIconId = IntentUtils.safeGetInt(bundle, WebApkMetaDataKeys.MASKABLE_ICON_ID, 0); + // There are a few WebAPKs with bad shells (between v105 and v114) that would previously + // cause chrome to crash. The check below fixes it. See crbug.com/1019318#c8 for details. + if (shellApkVersion >= 105 && shellApkVersion <= 114) { + try { + ApiCompatibilityUtils.getDrawable(res, primaryMaskableIconId); + } catch (Resources.NotFoundException e) { + primaryMaskableIconId = 0; + } + } + boolean isPrimaryIconMaskable = primaryMaskableIconId != 0 && ShortcutHelper.doesAndroidSupportMaskableIcons();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java new file mode 100644 index 0000000..46fbb1b --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/content/TabObserverRegistrarTest.java
@@ -0,0 +1,114 @@ +// 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.customtabs.content; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.MediumTest; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.util.CallbackHelper; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.ChromeSwitches; +import org.chromium.chrome.browser.customtabs.CustomTabActivity; +import org.chromium.chrome.browser.customtabs.CustomTabActivityTestRule; +import org.chromium.chrome.browser.customtabs.CustomTabsTestUtils; +import org.chromium.chrome.browser.tab.EmptyTabObserver; +import org.chromium.chrome.browser.tab.Tab; +import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver; +import org.chromium.chrome.browser.tabmodel.TabLaunchType; +import org.chromium.chrome.browser.tabmodel.TabModelSelector; +import org.chromium.chrome.test.ChromeJUnit4ClassRunner; +import org.chromium.content_public.browser.LoadUrlParams; +import org.chromium.content_public.browser.test.util.DOMUtils; +import org.chromium.content_public.browser.test.util.TestThreadUtils; +import org.chromium.net.test.EmbeddedTestServer; + +import java.util.ArrayList; +import java.util.List; + +/** + * Tests for {@link TabObserverRegistrar}. + */ +@RunWith(ChromeJUnit4ClassRunner.class) +@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE}) +public class TabObserverRegistrarTest { + private static class LoadUrlTabObserver extends EmptyTabObserver { + private List<String> mUrlLoadRequests = new ArrayList<>(); + + List<String> getLoadUrlRequests() { + return mUrlLoadRequests; + } + + @Override + public void onLoadUrl(Tab tab, LoadUrlParams params, int loadType) { + mUrlLoadRequests.add(params.getUrl()); + } + } + + @Rule + public CustomTabActivityTestRule mCustomTabActivityTestRule = new CustomTabActivityTestRule(); + + /** + * Tests that the TabObserver registered by + * {@link TabObserverRegistrar#registerActivityTabObserver()} switches when the active tab is + * switched. + */ + @Test + @MediumTest + public void testObserveActiveTab() throws Throwable { + EmbeddedTestServer testServer = mCustomTabActivityTestRule.getTestServer(); + final String windowOpenUrl = + testServer.getURL("/chrome/test/data/android/customtabs/test_window_open.html"); + final String url1 = testServer.getURL("/chrome/test/data/android/about.html"); + final String url2 = testServer.getURL("/chrome/test/data/android/simple.html"); + + mCustomTabActivityTestRule.startCustomTabActivityWithIntent( + CustomTabsTestUtils.createMinimalCustomTabIntent( + InstrumentationRegistry.getTargetContext(), windowOpenUrl)); + + // Register TabObserver via TabObserverRegistrar#registerActiveTabObserver() + CustomTabActivity customTabActivity = mCustomTabActivityTestRule.getActivity(); + TabObserverRegistrar tabObserverRegistrar = + customTabActivity.getComponent().resolveTabObserverRegistrar(); + LoadUrlTabObserver loadUrlTabObserver = new LoadUrlTabObserver(); + tabObserverRegistrar.registerActivityTabObserver(loadUrlTabObserver); + + final TabModelSelector tabSelector = customTabActivity.getTabModelSelector(); + final Tab initialActiveTab = tabSelector.getCurrentTab(); + + // Open and wait for popup. + final CallbackHelper openTabHelper = new CallbackHelper(); + TestThreadUtils.runOnUiThreadBlocking(() -> { + tabSelector.getModel(false).addObserver(new EmptyTabModelObserver() { + @Override + public void didAddTab(Tab tab, @TabLaunchType int type) { + openTabHelper.notifyCalled(); + } + }); + }); + DOMUtils.clickNode(mCustomTabActivityTestRule.getWebContents(), "new_window"); + openTabHelper.waitForCallback(0, 1); + + assertEquals(2, tabSelector.getModel(false).getCount()); + final Tab activeTab = tabSelector.getCurrentTab(); + assertNotEquals(activeTab, initialActiveTab); + + TestThreadUtils.runOnUiThreadBlocking(() -> { + android.util.Log.e("ABCD", "loadUrl0"); + initialActiveTab.loadUrl(new LoadUrlParams(url1)); + activeTab.loadUrl(new LoadUrlParams(url2)); + }); + + List<String> urlRequests = loadUrlTabObserver.getLoadUrlRequests(); + assertEquals(1, urlRequests.size()); + assertEquals(url2, urlRequests.get(0)); + } +}
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn index 4aa999c..48daff6 100644 --- a/chrome/app/vector_icons/BUILD.gn +++ b/chrome/app/vector_icons/BUILD.gn
@@ -85,6 +85,7 @@ "photo_camera.icon", "picture_in_picture_control_background.icon", "picture_in_picture_alt.icon", + "protected_content.icon", "qrcode_generator.icon", "reader_mode.icon", "reload_touch.icon",
diff --git a/chrome/app/vector_icons/protected_content.icon b/chrome/app/vector_icons/protected_content.icon new file mode 100644 index 0000000..eae3d0b --- /dev/null +++ b/chrome/app/vector_icons/protected_content.icon
@@ -0,0 +1,33 @@ +// 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. + +CANVAS_DIMENSIONS, 24, +MOVE_TO, 21, 17, +H_LINE_TO, 3, +V_LINE_TO, 5, +R_H_LINE_TO, 18, +R_V_LINE_TO, 12, +CLOSE, +R_MOVE_TO, 0, -14, +H_LINE_TO, 3, +R_CUBIC_TO, -1.11f, 0, -2, 0.89f, -2, 2, +R_V_LINE_TO, 12, +R_ARC_TO, 2, 2, 0, 0, 0, 2, 2, +R_H_LINE_TO, 5, +R_V_LINE_TO, 2, +R_H_LINE_TO, 8, +R_V_LINE_TO, -2, +R_H_LINE_TO, 5, +R_CUBIC_TO, 1.1f, 0, 1.99f, -0.9f, 1.99f, -2, +LINE_TO, 23, 5, +R_ARC_TO, 2, 2, 0, 0, 0, -2, -2, +CLOSE, +MOVE_TO, 10, 15, +R_LINE_TO, -4, -3.82f, +R_LINE_TO, 1.41f, -1.35f, +LINE_TO, 10, 12.3f, +LINE_TO, 16.59f, 6, +LINE_TO, 18, 7.36f, +LINE_TO, 10, 15, +CLOSE
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc index 5435137..96e2e5f 100644 --- a/chrome/browser/android/compositor/layer/overlay_panel_layer.cc +++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.cc
@@ -83,10 +83,48 @@ // Round values to avoid pixel gap between layers. bar_height = floor(bar_height); + // --------------------------------------------------------------------------- + // Content setup, to center in space below drag handle (when present). + // --------------------------------------------------------------------------- float bar_top_y = bar_offset_y; float bar_bottom = bar_top_y + bar_height; bool is_rtl = l10n_util::IsLayoutRtl(); + bool is_new_layout = rounded_bar_top_resource_id_ != kInvalidResourceID; + + int content_top_y = bar_top_y; + int content_height = bar_height; + int rounded_top_adjust = 0; + int rounded_shadow_top = 0; + gfx::Size rounded_bar_top_size; + gfx::PointF rounded_bar_top_position; + + ui::NinePatchResource* rounded_bar_top_resource = nullptr; + if (is_new_layout) { + content_top_y += bar_margin_top; + content_height -= bar_margin_top; + + rounded_bar_top_resource = + ui::NinePatchResource::From(resource_manager_->GetResource( + ui::ANDROID_RESOURCE_TYPE_STATIC, rounded_bar_top_resource_id_)); + + rounded_bar_top_size = + gfx::Size(rounded_bar_top_resource->size().width() - + rounded_bar_top_resource->padding().width(), + rounded_bar_top_resource->size().height() - + rounded_bar_top_resource->padding().height()); + + // TODO(donnd): fix correctly. + const int vertical_fudge_factor = 2; // Create an overlap to avoid a seam. + rounded_top_adjust = rounded_bar_top_size.height() - vertical_fudge_factor; + // This is the position of the side-shadows vertically. + // TODO(donnd): fix this so it's pixel perfect. + rounded_shadow_top = rounded_top_adjust; + + rounded_bar_top_position = + gfx::PointF(-rounded_bar_top_resource->padding().x(), + bar_top_y - rounded_top_adjust); + } // --------------------------------------------------------------------------- // Panel Shadow @@ -94,6 +132,8 @@ if (panel_shadow_resource_id_ != kInvalidResourceID) { if (panel_shadow_->parent() != layer_) { layer_->AddChild(panel_shadow_); + if (is_new_layout) + layer_->AddChild(panel_shadow_right_); } ui::NinePatchResource* panel_shadow_resource = ui::NinePatchResource::From(resource_manager_->GetResource( @@ -102,56 +142,61 @@ gfx::Size shadow_res_size = panel_shadow_resource->size(); gfx::Rect shadow_res_padding = panel_shadow_resource->padding(); - gfx::Size shadow_bounds(panel_width + shadow_res_size.width() - - shadow_res_padding.size().width(), - panel_height + shadow_res_size.height() - - shadow_res_padding.size().height()); panel_shadow_->SetUIResourceId(panel_shadow_resource->ui_resource()->id()); - panel_shadow_->SetBorder(panel_shadow_resource->Border(shadow_bounds)); panel_shadow_->SetAperture(panel_shadow_resource->aperture()); - panel_shadow_->SetBounds(shadow_bounds); - gfx::PointF shadow_position(-shadow_res_padding.origin().x(), - -shadow_res_padding.origin().y()); - panel_shadow_->SetPosition(shadow_position); - } + if (is_new_layout) { + DCHECK(rounded_bar_top_resource); - // --------------------------------------------------------------------------- - // Content setup, to center in space below drag handle (when present). - // --------------------------------------------------------------------------- - int content_top_y = bar_top_y; - int content_height = bar_height; - int rounded_top_adjust = 0; - if (rounded_bar_top_resource_id_ != kInvalidResourceID) { - content_top_y += bar_margin_top; - content_height -= bar_margin_top; + gfx::Size shadow_bounds(shadow_res_size.width(), + panel_height + shadow_res_size.height()); + panel_shadow_->SetBounds(shadow_bounds); + panel_shadow_->SetBorder(panel_shadow_resource->Border(shadow_bounds)); + // Position the top of the side shadow to the match the top of the + // rounded_bar_top shadow (which is indicated by its top padding). + // TODO(donnd): revisit side-shadow asset and positioning as discussed + // in https://crbug.com/1005975. + gfx::PointF shadow_position(-shadow_res_padding.size().width(), + bar_top_y - rounded_shadow_top); + panel_shadow_->SetPosition(shadow_position); + + // Do the right hand side as a mirror of the left shadow. + panel_shadow_right_->SetUIResourceId( + panel_shadow_resource->ui_resource()->id()); + panel_shadow_right_->SetAperture(panel_shadow_resource->aperture()); + panel_shadow_right_->SetBounds(shadow_bounds); + panel_shadow_right_->SetBorder( + panel_shadow_resource->Border(shadow_bounds)); + gfx::PointF right_shadow_position( + panel_width + shadow_res_padding.size().width(), + bar_top_y - rounded_shadow_top); + panel_shadow_right_->SetPosition(right_shadow_position); + + // Flip it from the left side to the right side. + gfx::Transform flip_right_transform; + flip_right_transform.RotateAboutYAxis(180.0); + panel_shadow_right_->SetTransform(flip_right_transform); + } else { + gfx::Size shadow_bounds(panel_width + shadow_res_size.width() - + shadow_res_padding.size().width(), + panel_height + shadow_res_size.height() - + shadow_res_padding.size().height()); + panel_shadow_->SetBounds(shadow_bounds); + panel_shadow_->SetBorder(panel_shadow_resource->Border(shadow_bounds)); + gfx::PointF shadow_position(-shadow_res_padding.origin().x(), + -shadow_res_padding.origin().y()); + panel_shadow_->SetPosition(shadow_position); + } } // --------------------------------------------------------------------------- // Rounded Bar Top // --------------------------------------------------------------------------- - if (rounded_bar_top_resource_id_ != kInvalidResourceID) { + if (is_new_layout) { + DCHECK(rounded_bar_top_resource_id_ != kInvalidResourceID); rounded_bar_top_->SetIsDrawable(true); - ui::NinePatchResource* rounded_bar_top_resource = - ui::NinePatchResource::From(resource_manager_->GetResource( - ui::ANDROID_RESOURCE_TYPE_STATIC, rounded_bar_top_resource_id_)); - DCHECK(rounded_bar_top_resource); - const gfx::Size rounded_bar_top_size( - rounded_bar_top_resource->size().width() - - rounded_bar_top_resource->padding().width(), - rounded_bar_top_resource->size().height() - - rounded_bar_top_resource->padding().height()); - - // TODO(donnd): fix correctly. - const int vertical_fudge_factor = 2; // Create an overlap to avoid a seam. - rounded_top_adjust = rounded_bar_top_size.height() - vertical_fudge_factor; - - gfx::PointF rounded_bar_top_position( - -rounded_bar_top_resource->padding().x(), - bar_top_y - rounded_top_adjust); - gfx::Size bounds(panel_width - rounded_bar_top_size.width(), rounded_bar_top_resource->size().height()); @@ -426,6 +471,7 @@ : resource_manager_(resource_manager), layer_(cc::Layer::Create()), panel_shadow_(cc::NinePatchLayer::Create()), + panel_shadow_right_(cc::NinePatchLayer::Create()), rounded_bar_top_(cc::NinePatchLayer::Create()), bar_background_(cc::SolidColorLayer::Create()), bar_text_(cc::UIResourceLayer::Create()), @@ -444,10 +490,15 @@ layer_->SetMasksToBounds(false); layer_->SetIsDrawable(true); - // Panel Shadow + // Panel Shadow -- shadow on the left side of the panel, or the whole panel + // when not using the new layout. panel_shadow_->SetIsDrawable(true); panel_shadow_->SetFillCenter(false); + // Panel Shadow Right -- shadow on the right side of the panel. + panel_shadow_right_->SetIsDrawable(true); + panel_shadow_right_->SetFillCenter(false); + // Rounded Bar Top // Puts the layer near the bottom -- we'll decide if it's actually drawable // later.
diff --git a/chrome/browser/android/compositor/layer/overlay_panel_layer.h b/chrome/browser/android/compositor/layer/overlay_panel_layer.h index 9305387..bfae8c41 100644 --- a/chrome/browser/android/compositor/layer/overlay_panel_layer.h +++ b/chrome/browser/android/compositor/layer/overlay_panel_layer.h
@@ -82,6 +82,7 @@ scoped_refptr<cc::Layer> layer_; scoped_refptr<cc::NinePatchLayer> panel_shadow_; + scoped_refptr<cc::NinePatchLayer> panel_shadow_right_; scoped_refptr<cc::NinePatchLayer> rounded_bar_top_; scoped_refptr<cc::SolidColorLayer> bar_background_; scoped_refptr<cc::UIResourceLayer> bar_text_;
diff --git a/chrome/browser/android/provider/chrome_browser_provider.cc b/chrome/browser/android/provider/chrome_browser_provider.cc index 2e475ae9..1e9212a 100644 --- a/chrome/browser/android/provider/chrome_browser_provider.cc +++ b/chrome/browser/android/provider/chrome_browser_provider.cc
@@ -27,7 +27,6 @@ #include "chrome/browser/bookmarks/bookmark_model_factory.h" #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/favicon/favicon_service_factory.h" #include "chrome/browser/history/android/sqlite_cursor.h" #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/top_sites_factory.h" @@ -37,7 +36,6 @@ #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_utils.h" #include "components/bookmarks/managed/managed_bookmark_service.h" -#include "components/favicon/core/favicon_service.h" #include "components/history/core/browser/android/android_history_types.h" #include "components/history/core/browser/top_sites.h" #include "components/search_engines/template_url.h" @@ -45,7 +43,6 @@ #include "content/public/browser/browser_thread.h" #include "ui/base/layout.h" #include "ui/base/resource/resource_bundle.h" -#include "ui/gfx/favicon_size.h" using base::android::AttachCurrentThread; using base::android::CheckException; @@ -315,7 +312,7 @@ // ------------- Aynchronous requests classes ------------- // // Base class for asynchronous blocking requests to Chromium services. -// Service: type of the service to use (e.g. HistoryService, FaviconService). +// Service: type of the service to use (e.g. HistoryService). template <typename Service> class AsyncServiceRequest : protected BlockingUIThreadAsyncRequest { public: @@ -797,8 +794,6 @@ profile_ = g_browser_process->profile_manager()->GetLastUsedProfile(); bookmark_model_ = BookmarkModelFactory::GetForBrowserContext(profile_); top_sites_ = TopSitesFactory::GetForProfile(profile_); - favicon_service_ = FaviconServiceFactory::GetForProfile( - profile_, ServiceAccessType::EXPLICIT_ACCESS), service_.reset(new AndroidHistoryProviderService(profile_)); // Register as observer for service we are interested.
diff --git a/chrome/browser/android/provider/chrome_browser_provider.h b/chrome/browser/android/provider/chrome_browser_provider.h index 87c31538..70527116 100644 --- a/chrome/browser/android/provider/chrome_browser_provider.h +++ b/chrome/browser/android/provider/chrome_browser_provider.h
@@ -21,10 +21,6 @@ class AndroidHistoryProviderService; class Profile; -namespace favicon { -class FaviconService; -} - namespace history { class TopSites; } @@ -139,50 +135,6 @@ const base::android::JavaParamRef<jstring>& selections, const base::android::JavaParamRef<jobjectArray>& selection_args); - // Custom provider API methods. --------------------------------------------- - jlong CreateBookmarksFolderOnce( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jstring>& title, - jlong parent_id); - - void RemoveAllUserBookmarks(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj); - - base::android::ScopedJavaLocalRef<jobject> GetEditableBookmarkFolders( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj); - - base::android::ScopedJavaLocalRef<jobject> GetBookmarkNode( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - jlong id, - jboolean get_parent, - jboolean get_children); - - base::android::ScopedJavaLocalRef<jobject> GetMobileBookmarksFolder( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj); - - jboolean IsBookmarkInMobileBookmarksBranch( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - jlong id); - - jboolean BookmarkNodeExists(JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - jlong id); - - base::android::ScopedJavaLocalRef<jbyteArray> GetFaviconOrTouchIcon( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jstring>& url); - - base::android::ScopedJavaLocalRef<jbyteArray> GetThumbnail( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jstring>& url); - private: ~ChromeBrowserProvider() override; @@ -223,7 +175,6 @@ Profile* profile_; bookmarks::BookmarkModel* bookmark_model_; scoped_refptr<history::TopSites> top_sites_; - favicon::FaviconService* favicon_service_; std::unique_ptr<AndroidHistoryProviderService> service_;
diff --git a/chrome/browser/android/vr/BUILD.gn b/chrome/browser/android/vr/BUILD.gn index aab2e058..3d62eaf 100644 --- a/chrome/browser/android/vr/BUILD.gn +++ b/chrome/browser/android/vr/BUILD.gn
@@ -27,6 +27,7 @@ "gl_browser_interface.h", "gvr_consent_helper_impl.cc", "gvr_consent_helper_impl.h", + "gvr_gamepad_data.h", "gvr_graphics_delegate.cc", "gvr_graphics_delegate.h", "gvr_input_delegate.cc",
diff --git a/chrome/browser/android/vr/gl_browser_interface.h b/chrome/browser/android/vr/gl_browser_interface.h index ad0ffc4..620e43a 100644 --- a/chrome/browser/android/vr/gl_browser_interface.h +++ b/chrome/browser/android/vr/gl_browser_interface.h
@@ -8,9 +8,9 @@ #include <memory> #include "base/android/jni_weak_ref.h" +#include "chrome/browser/android/vr/gvr_gamepad_data.h" #include "chrome/browser/vr/assets_load_status.h" #include "chrome/browser/vr/ui_test_input.h" -#include "device/vr/android/gvr/gvr_gamepad_data_provider.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h" #include "ui/gfx/transform.h" @@ -36,7 +36,7 @@ virtual void SendRequestPresentReply(device::mojom::XRSessionPtr) = 0; virtual void DialogSurfaceCreated(jobject surface, gl::SurfaceTexture* texture) = 0; - virtual void UpdateGamepadData(device::GvrGamepadData) = 0; + virtual void UpdateGamepadData(GvrGamepadData) = 0; virtual void ToggleCardboardGamepad(bool enabled) = 0; };
diff --git a/chrome/browser/android/vr/gvr_gamepad_data.h b/chrome/browser/android/vr/gvr_gamepad_data.h new file mode 100644 index 0000000..2961709 --- /dev/null +++ b/chrome/browser/android/vr/gvr_gamepad_data.h
@@ -0,0 +1,35 @@ +// 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. + +#ifndef CHROME_BROWSER_ANDROID_VR_GVR_GAMEPAD_DATA_H_ +#define CHROME_BROWSER_ANDROID_VR_GVR_GAMEPAD_DATA_H_ + +#include "ui/gfx/geometry/quaternion.h" +#include "ui/gfx/geometry/vector2d_f.h" +#include "ui/gfx/geometry/vector3d_f.h" + +namespace vr { + +// Subset of GVR controller data needed for the gamepad API. Filled in +// by vr_shell's VrController. +struct GvrGamepadData { + GvrGamepadData() + : timestamp(0), + is_touching(false), + controller_button_pressed(false), + right_handed(true), + connected(false) {} + int64_t timestamp; + gfx::Vector2dF touch_pos; + gfx::Quaternion orientation; + gfx::Vector3dF accel; + gfx::Vector3dF gyro; + bool is_touching; + bool controller_button_pressed; + bool right_handed; + bool connected; +}; + +} // namespace vr +#endif // CHROME_BROWSER_ANDROID_VR_GVR_GAMEPAD_DATA_H_
diff --git a/chrome/browser/android/vr/gvr_input_delegate.cc b/chrome/browser/android/vr/gvr_input_delegate.cc index 847b0779..a20748b 100644 --- a/chrome/browser/android/vr/gvr_input_delegate.cc +++ b/chrome/browser/android/vr/gvr_input_delegate.cc
@@ -19,7 +19,7 @@ namespace { constexpr gfx::Vector3dF kForwardVector = {0.0f, 0.0f, -1.0f}; -device::Gamepad CreateGamepad(const device::GvrGamepadData& data) { +device::Gamepad CreateGamepad(const vr::GvrGamepadData& data) { device::Gamepad gamepad; // Unless the controller state is updated on a different thread, @@ -81,7 +81,7 @@ bool is_webxr_frame) { controller_->UpdateState(head_pose); - device::GvrGamepadData controller_data = controller_->GetGamepadData(); + GvrGamepadData controller_data = controller_->GetGamepadData(); if (!is_webxr_frame) controller_data.connected = false; browser_->UpdateGamepadData(controller_data);
diff --git a/chrome/browser/android/vr/vr_controller.cc b/chrome/browser/android/vr/vr_controller.cc index 5900c57..89cd50c3 100644 --- a/chrome/browser/android/vr/vr_controller.cc +++ b/chrome/browser/android/vr/vr_controller.cc
@@ -93,8 +93,8 @@ controller_api_->Pause(); } -device::GvrGamepadData VrController::GetGamepadData() { - device::GvrGamepadData pad = {}; +GvrGamepadData VrController::GetGamepadData() { + GvrGamepadData pad = {}; pad.connected = IsConnected(); pad.timestamp = controller_state_->GetLastOrientationTimestamp();
diff --git a/chrome/browser/android/vr/vr_controller.h b/chrome/browser/android/vr/vr_controller.h index e58b023..bfde641 100644 --- a/chrome/browser/android/vr/vr_controller.h +++ b/chrome/browser/android/vr/vr_controller.h
@@ -10,10 +10,10 @@ #include "base/macros.h" #include "base/time/time.h" +#include "chrome/browser/android/vr/gvr_gamepad_data.h" #include "chrome/browser/android/vr/gvr_util.h" #include "chrome/browser/vr/gesture_detector.h" #include "chrome/browser/vr/platform_controller.h" -#include "device/vr/android/gvr/gvr_gamepad_data_provider.h" #include "third_party/gvr-android-sdk/src/libraries/headers/vr/gvr/capi/include/gvr_types.h" #include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/quaternion.h" @@ -47,7 +47,7 @@ // Must be called when the Activity gets OnPause(). void OnPause(); - device::GvrGamepadData GetGamepadData(); + GvrGamepadData GetGamepadData(); // Called once per frame to update controller state. void UpdateState(const gfx::Transform& head_pose);
diff --git a/chrome/browser/android/vr/vr_gl_thread.cc b/chrome/browser/android/vr/vr_gl_thread.cc index 7169942a..0753c3d 100644 --- a/chrome/browser/android/vr/vr_gl_thread.cc +++ b/chrome/browser/android/vr/vr_gl_thread.cc
@@ -118,7 +118,7 @@ weak_vr_shell_, std::move(session))); } -void VrGLThread::UpdateGamepadData(device::GvrGamepadData pad) { +void VrGLThread::UpdateGamepadData(GvrGamepadData pad) { DCHECK(OnGlThread()); main_thread_task_runner_->PostTask( FROM_HERE,
diff --git a/chrome/browser/android/vr/vr_gl_thread.h b/chrome/browser/android/vr/vr_gl_thread.h index ffcf816..ca4d3bd 100644 --- a/chrome/browser/android/vr/vr_gl_thread.h +++ b/chrome/browser/android/vr/vr_gl_thread.h
@@ -71,7 +71,7 @@ void SendRequestPresentReply(device::mojom::XRSessionPtr) override; void DialogSurfaceCreated(jobject surface, gl::SurfaceTexture* texture) override; - void UpdateGamepadData(device::GvrGamepadData) override; + void UpdateGamepadData(GvrGamepadData) override; void ToggleCardboardGamepad(bool enabled) override; // BrowserRendererBrowserInterface implementation (BrowserRenderer calling to
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc index 2e3382a..c3e9c4d 100644 --- a/chrome/browser/android/vr/vr_shell.cc +++ b/chrome/browser/android/vr/vr_shell.cc
@@ -1073,7 +1073,7 @@ dialog_gesture_target_->DispatchInputEvent(std::move(event)); } -void VrShell::UpdateGamepadData(device::GvrGamepadData pad) { +void VrShell::UpdateGamepadData(GvrGamepadData pad) { if (gvr_gamepad_source_active_ != pad.connected) ToggleGvrGamepad(pad.connected); }
diff --git a/chrome/browser/android/vr/vr_shell.h b/chrome/browser/android/vr/vr_shell.h index ea465f02..842c56ee 100644 --- a/chrome/browser/android/vr/vr_shell.h +++ b/chrome/browser/android/vr/vr_shell.h
@@ -16,6 +16,7 @@ #include "base/single_thread_task_runner.h" #include "base/strings/string16.h" #include "base/timer/timer.h" +#include "chrome/browser/android/vr/gvr_gamepad_data.h" #include "chrome/browser/ui/page_info/page_info_ui.h" #include "chrome/browser/ui/toolbar/chrome_location_bar_model_delegate.h" #include "chrome/browser/vr/assets_load_status.h" @@ -28,7 +29,6 @@ #include "chrome/browser/vr/ui_initial_state.h" #include "chrome/browser/vr/ui_unsupported_mode.h" #include "content/public/browser/web_contents_observer.h" -#include "device/vr/android/gvr/gvr_gamepad_data_provider.h" #include "device/vr/public/cpp/session_mode.h" #include "device/vr/public/mojom/vr_service.mojom.h" #include "device/vr/vr_device.h" @@ -65,8 +65,7 @@ // The native instance of the Java VrShell. This class is not threadsafe and // must only be used on the UI thread. -class VrShell : device::GvrGamepadDataProvider, - VoiceResultDelegate, +class VrShell : VoiceResultDelegate, public ChromeLocationBarModelDelegate, public PageInfoUI { public: @@ -255,8 +254,7 @@ device::mojom::VRDisplayInfoPtr display_info, device::mojom::XRRuntimeSessionOptionsPtr options); - // device::GvrGamepadDataProvider implementation. - void UpdateGamepadData(device::GvrGamepadData) override; + void UpdateGamepadData(GvrGamepadData); // ChromeLocationBarModelDelegate implementation. content::WebContents* GetActiveWebContents() const override;
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc index fafa707..3276010 100644 --- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc +++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
@@ -314,13 +314,15 @@ DISALLOW_COPY_AND_ASSIGN(TestHost); }; -class ExtensionAppShimHandlerTest : public testing::Test { +class ExtensionAppShimHandlerTestBase : public testing::Test { protected: - ExtensionAppShimHandlerTest() - : delegate_(new MockDelegate), - handler_(new TestingExtensionAppShimHandler(delegate_)), - profile_path_a_("Profile A"), - profile_path_b_("Profile B") { + ExtensionAppShimHandlerTestBase() {} + + void SetUp() override { + delegate_ = new MockDelegate; + handler_.reset(new TestingExtensionAppShimHandler(delegate_)); + profile_path_a_ = base::FilePath("Profile A"); + profile_path_b_ = base::FilePath("Profile B"); AppShimHostBootstrap::SetClient(handler_.get()); bootstrap_aa_ = (new TestingAppShimHostBootstrap( profile_path_a_, kTestAppIdA, @@ -421,7 +423,7 @@ .WillRepeatedly(Return()); } - ~ExtensionAppShimHandlerTest() override { + ~ExtensionAppShimHandlerTestBase() override { host_aa_unique_.reset(); host_ab_unique_.reset(); host_bb_unique_.reset(); @@ -529,7 +531,34 @@ scoped_refptr<const Extension> extension_b_; private: - DISALLOW_COPY_AND_ASSIGN(ExtensionAppShimHandlerTest); + DISALLOW_COPY_AND_ASSIGN(ExtensionAppShimHandlerTestBase); +}; + +class ExtensionAppShimHandlerTest : public ExtensionAppShimHandlerTestBase { + public: + void SetUp() override { + scoped_features_.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kAppShimMultiProfile}); + ExtensionAppShimHandlerTestBase::SetUp(); + } + + private: + base::test::ScopedFeatureList scoped_features_; +}; + +class ExtensionAppShimHandlerTestMultiProfile + : public ExtensionAppShimHandlerTestBase { + public: + void SetUp() override { + scoped_features_.InitWithFeatures( + /*enabled_features=*/{features::kAppShimMultiProfile}, + /*disabled_features=*/{}); + ExtensionAppShimHandlerTestBase::SetUp(); + } + + private: + base::test::ScopedFeatureList scoped_features_; }; TEST_F(ExtensionAppShimHandlerTest, LaunchProfileNotFound) { @@ -866,12 +895,7 @@ EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA)); } -TEST_F(ExtensionAppShimHandlerTest, MultiProfile) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAppShimMultiProfile}, - /*disabled_features=*/{}); - +TEST_F(ExtensionAppShimHandlerTestMultiProfile, MultiProfile) { // Test with a bookmark app (host is shared). { // Create a host for profile A. @@ -907,12 +931,7 @@ } } -TEST_F(ExtensionAppShimHandlerTest, MultiProfileShimLaunch) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAppShimMultiProfile}, - /*disabled_features=*/{}); - +TEST_F(ExtensionAppShimHandlerTestMultiProfile, MultiProfileShimLaunch) { delegate_->SetHostForCreate(std::move(host_aa_unique_)); ShimLaunchedCallback launched_callback; delegate_->SetCaptureShimLaunchedCallback(&launched_callback); @@ -939,12 +958,7 @@ EXPECT_TRUE(terminated_callback); } -TEST_F(ExtensionAppShimHandlerTest, MultiProfileSelectMenu) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAppShimMultiProfile}, - /*disabled_features=*/{}); - +TEST_F(ExtensionAppShimHandlerTestMultiProfile, MultiProfileSelectMenu) { delegate_->SetHostForCreate(std::move(host_aa_unique_)); ShimLaunchedCallback launched_callback; delegate_->SetCaptureShimLaunchedCallback(&launched_callback); @@ -980,12 +994,7 @@ host_aa_->ProfileSelectedFromMenu(profile_path_b_); } -TEST_F(ExtensionAppShimHandlerTest, ProfileMenuOneProfile) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAppShimMultiProfile}, - /*disabled_features=*/{}); - +TEST_F(ExtensionAppShimHandlerTestMultiProfile, ProfileMenuOneProfile) { // Set this app to be installed for profile A. { auto item_a = chrome::mojom::ProfileMenuItem::New(); @@ -1048,12 +1057,7 @@ EXPECT_FALSE(delegate_->RunGetProfilesForAppCallback()); } -TEST_F(ExtensionAppShimHandlerTest, FindProfileFromBadProfile) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAppShimMultiProfile}, - /*disabled_features=*/{}); - +TEST_F(ExtensionAppShimHandlerTestMultiProfile, FindProfileFromBadProfile) { // Set this app to be installed for profile A. { auto item_a = chrome::mojom::ProfileMenuItem::New(); @@ -1076,12 +1080,7 @@ EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA)); } -TEST_F(ExtensionAppShimHandlerTest, FindProfileFromNoProfile) { - base::test::ScopedFeatureList scoped_features; - scoped_features.InitWithFeatures( - /*enabled_features=*/{features::kAppShimMultiProfile}, - /*disabled_features=*/{}); - +TEST_F(ExtensionAppShimHandlerTestMultiProfile, FindProfileFromNoProfile) { // Set this app to be installed for profile A. { auto item_a = chrome::mojom::ProfileMenuItem::New();
diff --git a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc index 0765b1e..66918fd 100644 --- a/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc +++ b/chrome/browser/chromeos/certificate_provider/certificate_provider_service.cc
@@ -19,7 +19,7 @@ #include "base/strings/string_piece.h" #include "base/task_runner.h" #include "base/task_runner_util.h" -#include "base/threading/thread_task_runner_handle.h" +#include "base/threading/sequenced_task_runner_handle.h" #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h" #include "net/base/net_errors.h" #include "third_party/boringssl/src/include/openssl/digest.h" @@ -32,14 +32,14 @@ void PostSignResult(net::SSLPrivateKey::SignCallback callback, net::Error error, const std::vector<uint8_t>& signature) { - base::ThreadTaskRunnerHandle::Get()->PostTask( + base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), error, signature)); } void PostIdentities( base::OnceCallback<void(net::ClientCertIdentityList)> callback, net::ClientCertIdentityList certs) { - base::ThreadTaskRunnerHandle::Get()->PostTask( + base::SequencedTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(std::move(callback), std::move(certs))); }
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 befc973..5f3d485 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -72,7 +72,6 @@ #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window_registry.h" #include "google_apis/drive/auth_service.h" -#include "net/base/hex_utils.h" #include "services/network/public/cpp/shared_url_loader_factory.h" #include "storage/common/file_system/file_system_types.h" #include "storage/common/file_system/file_system_util.h" @@ -1093,7 +1092,10 @@ const std::unique_ptr<Params> params(Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); - std::string input = net::HexDecode(params->bytes); + std::string input; + if (!base::HexStringToString(params->bytes, &input)) + input.clear(); + std::string encoding; bool success = base::DetectEncoding(input, &encoding); return RespondNow(OneArgument(std::make_unique<base::Value>(
diff --git a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc index 89655fe..341455c 100644 --- a/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc
@@ -557,8 +557,7 @@ EXPECT_EQ(base::Value(base::Value::Type::LIST), *fast_reinstall_packages); } -// Disabled due to flakiness: https://crbug.com/982161 -IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, DISABLED_NoRecommendedApps) { +IN_PROC_BROWSER_TEST_F(RecommendAppsScreenTest, NoRecommendedApps) { recommend_apps_screen_->Show(); OobeScreenWaiter screen_waiter(RecommendAppsScreenView::kScreenId); @@ -587,8 +586,7 @@ test::OobeJS().CreateDisplayedWaiter(true, skip_button)->Wait(); test::OobeJS().ExpectEnabledPath(skip_button); - test::OobeJS().ExpectPathDisplayed(false, install_button); - test::OobeJS().ExpectPathDisplayed(false, retry_button); + test::OobeJS().ExpectDisabledPath(install_button); test::OobeJS().ExpectPathDisplayed(false, retry_button); test::OobeJS().TapOnPath(skip_button);
diff --git a/chrome/browser/extensions/external_provider_impl_unittest.cc b/chrome/browser/extensions/external_provider_impl_unittest.cc index e044d3a3..bbd2f29 100644 --- a/chrome/browser/extensions/external_provider_impl_unittest.cc +++ b/chrome/browser/extensions/external_provider_impl_unittest.cc
@@ -48,6 +48,11 @@ #include "components/user_manager/scoped_user_manager.h" #endif +#if defined(OS_WIN) +#include "base/test/test_reg_util_win.h" +#include "base/win/registry.h" +#endif + namespace extensions { namespace { @@ -59,6 +64,13 @@ const char kExternalAppId[] = "kekdneafjmhmndejhmbcadfiiofngffo"; #endif +#if defined(OS_WIN) +const char kExternalAppCrxPath[] = + "external\\kekdneafjmhmndejhmbcadfiiofngffo.crx"; +const wchar_t kExternalAppRegistryKey[] = + L"Software\\Google\\Chrome\\Extensions\\kekdneafjmhmndejhmbcadfiiofngffo"; +#endif + class ExternalProviderImplTest : public ExtensionServiceTestBase { public: ExternalProviderImplTest() {} @@ -92,8 +104,25 @@ } void OverrideExternalExtensionsPath() { + // Windows doesn't use the provider that installs the |kExternalAppId| + // extension implicitly, so to test that the blocking policy works on + // Windows it is installed through a Windows-specific registry provider. +#if defined(OS_WIN) + EXPECT_NO_FATAL_FAILURE( + registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER)); + EXPECT_EQ(ERROR_SUCCESS, + external_extension_key_.Create( + HKEY_CURRENT_USER, kExternalAppRegistryKey, KEY_ALL_ACCESS)); + EXPECT_EQ(ERROR_SUCCESS, + external_extension_key_.WriteValue( + L"path", + data_dir().AppendASCII(kExternalAppCrxPath).value().c_str())); + EXPECT_EQ(ERROR_SUCCESS, + external_extension_key_.WriteValue(L"version", L"1")); +#else external_externsions_overrides_.reset(new base::ScopedPathOverride( chrome::DIR_EXTERNAL_EXTENSIONS, data_dir().AppendASCII("external"))); +#endif } void SetExternalExtensionsBlockedByPolicy(const bool block_external) { @@ -174,6 +203,12 @@ chromeos::system::ScopedFakeStatisticsProvider fake_statistics_provider_; #endif +#if defined(OS_WIN) + // Registry key pointing to the external extension for Windows. + base::win::RegKey external_extension_key_; + registry_util::RegistryOverrideManager registry_override_manager_; +#endif + DISALLOW_COPY_AND_ASSIGN(ExternalProviderImplTest); };
diff --git a/chrome/browser/media/encrypted_media_browsertest.cc b/chrome/browser/media/encrypted_media_browsertest.cc index 3208b37..4d688be 100644 --- a/chrome/browser/media/encrypted_media_browsertest.cc +++ b/chrome/browser/media/encrypted_media_browsertest.cc
@@ -61,8 +61,6 @@ "org.chromium.externalclearkey.fileiotest"; const char kExternalClearKeyInitializeFailKeySystem[] = "org.chromium.externalclearkey.initializefail"; -const char kExternalClearKeyOutputProtectionTestKeySystem[] = - "org.chromium.externalclearkey.outputprotectiontest"; const char kExternalClearKeyPlatformVerificationTestKeySystem[] = "org.chromium.externalclearkey.platformverificationtest"; const char kExternalClearKeyCrashKeySystem[] = @@ -350,6 +348,17 @@ PlayCount::ONCE, expected_title); } + void TestOutputProtection(bool create_recorder_before_media_keys) { + // Make sure the Clear Key CDM is properly registered in CdmRegistry. + EXPECT_TRUE(IsLibraryCdmRegistered(media::kClearKeyCdmGuid)); + + base::StringPairs query_params; + if (create_recorder_before_media_keys) + query_params.emplace_back("createMediaRecorderBeforeMediaKeys", "1"); + RunMediaTestPage("eme_and_get_display_media.html", query_params, + kUnitTestSuccess, true); + } + protected: void SetUpCommandLine(base::CommandLine* command_line) override { EncryptedMediaTestBase::SetUpCommandLine(command_line); @@ -358,6 +367,10 @@ command_line->AppendSwitchASCII( switches::kOverrideEnabledCdmInterfaceVersion, base::NumberToString(GetCdmInterfaceVersion())); + // The output protection tests create a MediaRecorder on a MediaStream, + // so this allows for a fake stream to be created. + command_line->AppendSwitch(switches::kUseFakeUIForMediaStream); + command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream); } }; @@ -384,7 +397,6 @@ command_line->AppendSwitch(switches::kIncognito); } }; - #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) // Tests encrypted media playback with a combination of parameters: @@ -795,11 +807,13 @@ TestNonPlaybackCases(kExternalClearKeyFileIOTestKeySystem, kUnitTestSuccess); } -// TODO(xhwang): Investigate how to fake capturing activities to test the -// network link detection logic in OutputProtectionProxy. -IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, OutputProtectionTest) { - TestNonPlaybackCases(kExternalClearKeyOutputProtectionTestKeySystem, - kUnitTestSuccess); +// Output protection tests. +IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, OutputProtectionBeforeMediaKeys) { + TestOutputProtection(/*create_recorder_before_media_keys=*/true); +} + +IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, OutputProtectionAfterMediaKeys) { + TestOutputProtection(/*create_recorder_before_media_keys=*/false); } IN_PROC_BROWSER_TEST_P(ECKEncryptedMediaTest, PlatformVerificationTest) { @@ -963,5 +977,4 @@ kExternalClearKeyKeySystem, query_params, media::kEnded); } - #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc index 6d54a5b4..541df95b 100644 --- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc +++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -175,7 +175,8 @@ hint_cache_(std::make_unique<optimization_guide::HintCache>( std::make_unique<optimization_guide::OptimizationGuideStore>( database_provider, - profile_path, + profile_path.AddExtensionASCII( + optimization_guide::kOptimizationGuideHintStore), background_task_runner_))), top_host_provider_(top_host_provider), url_loader_factory_(url_loader_factory),
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc index 52382c4..4f44f8a 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer.cc
@@ -37,6 +37,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "net/base/net_errors.h" +#include "services/metrics/public/cpp/metrics_utils.h" #include "services/metrics/public/cpp/ukm_builders.h" #include "services/metrics/public/cpp/ukm_recorder.h" #include "third_party/blink/public/mojom/web_feature/web_feature.mojom.h" @@ -605,7 +606,9 @@ 10) .SetAdVideoBytes(aggregate_frame_data_->GetAdNetworkBytesForMime( FrameData::ResourceMimeType::kVideo) >> - 10); + 10) + .SetMainframeAdBytes(ukm::GetExponentialBucketMinForBytes( + main_frame_data_->ad_network_bytes())); // Record cpu metrics for the page. builder.SetAdCpuTime(
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc index 744fd2d..6e34e3ad 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -1229,6 +1229,10 @@ 0); EXPECT_GT( *ukm_recorder.GetEntryMetric( + entries.front(), ukm::builders::AdPageLoad::kMainframeAdBytesName), + 0); + EXPECT_GT( + *ukm_recorder.GetEntryMetric( entries.front(), ukm::builders::AdPageLoad::kAdBytesPerSecondName), 0);
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc index c973711..d49f308 100644 --- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc +++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_unittest.cc
@@ -1112,6 +1112,15 @@ // Verify page total for network bytes. histogram_tester().ExpectUniqueSample( SuffixedHistogram("Resources.Bytes.Ads2"), 20, 1); + + // Verify main frame ad bytes recorded in UKM. + auto entries = test_ukm_recorder().GetEntriesByName( + ukm::builders::AdPageLoad::kEntryName); + EXPECT_EQ(1u, entries.size()); + EXPECT_EQ( + *test_ukm_recorder().GetEntryMetric( + entries.front(), ukm::builders::AdPageLoad::kMainframeAdBytesName), + ukm::GetExponentialBucketMinForBytes(10 * 1024)); } // Tests that memory cache ad bytes are recorded correctly. @@ -1184,6 +1193,10 @@ entries.front(), ukm::builders::AdPageLoad::kAdBytesPerSecondAfterInteractiveName), 0); + EXPECT_EQ( + *test_ukm_recorder().GetEntryMetric( + entries.front(), ukm::builders::AdPageLoad::kMainframeAdBytesName), + ukm::GetExponentialBucketMinForBytes(20 * 1024)); EXPECT_EQ(*ukm_recorder.GetEntryMetric( entries.front(), ukm::builders::AdPageLoad::kAdCpuTimeName), 500);
diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc index d062a277..71d06fc 100644 --- a/chrome/browser/password_manager/password_manager_browsertest.cc +++ b/chrome/browser/password_manager/password_manager_browsertest.cc
@@ -3310,8 +3310,16 @@ TabStripModel::ADD_ACTIVE); } +// Flaky on Linux and Windows. http://crbug.com/1022531 +#if defined(OS_LINUX) || defined(OS_WIN) +#define MAYBE_FillWhenFormWithHiddenUsername \ + DISABLED_FillWhenFormWithHiddenUsername +#else +#define MAYBE_FillWhenFormWithHiddenUsername \ + FillWhenFormWithHiddenUsername +#endif IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, - FillWhenFormWithHiddenUsername) { + MAYBE_FillWhenFormWithHiddenUsername) { // At first let us save a credential to the password store. scoped_refptr<password_manager::TestPasswordStore> password_store = static_cast<password_manager::TestPasswordStore*>(
diff --git a/chrome/browser/pdf/pdf_extension_test.cc b/chrome/browser/pdf/pdf_extension_test.cc index f974c9b..56079c34 100644 --- a/chrome/browser/pdf/pdf_extension_test.cc +++ b/chrome/browser/pdf/pdf_extension_test.cc
@@ -69,6 +69,8 @@ #include "content/public/common/context_menu_params.h" #include "content/public/common/mime_handler_view_mode.h" #include "content/public/common/url_constants.h" +#include "content/public/test/accessibility_notification_waiter.h" +#include "content/public/test/browser_accessibility.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/dump_accessibility_test_helper.h" #include "content/public/test/hit_test_region_observer.h" @@ -81,6 +83,7 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "pdf/pdf_features.h" #include "services/network/public/cpp/features.h" +#include "ui/accessibility/ax_action_data.h" #include "ui/accessibility/ax_enum_util.h" #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node.h" @@ -2515,12 +2518,13 @@ // Find the embedded PDF and dump the accessibility tree. content::FindAccessibilityNodeCriteria find_criteria; find_criteria.role = ax::mojom::Role::kEmbeddedObject; - content::BrowserAccessibility* pdf_root = + content::TestBrowserAccessibility* pdf_root = content::FindAccessibilityNode(guest_contents, find_criteria); CHECK(pdf_root); base::string16 actual_contents_utf16; - formatter->FormatAccessibilityTree(pdf_root, &actual_contents_utf16); + content::TestBrowserAccessibility::FormatAccessibilityTree( + formatter.get(), pdf_root, &actual_contents_utf16); std::string actual_contents = base::UTF16ToUTF8(actual_contents_utf16); std::vector<std::string> actual_lines = @@ -2626,3 +2630,38 @@ IN_PROC_BROWSER_TEST_P(PDFExtensionAccessibilityTreeDumpTest, TextStyle) { RunPDFTest(FILE_PATH_LITERAL("text-style.pdf")); } + +// This test suite validates the navigation done using the accessibility client. +using PDFExtensionAccessibilityNavigationTest = PDFExtensionTest; + +IN_PROC_BROWSER_TEST_F(PDFExtensionAccessibilityNavigationTest, + LinkNavigation) { + // Enable accessibility and load the test file. + content::BrowserAccessibilityState::GetInstance()->EnableAccessibility(); + GURL url(embedded_test_server()->GetURL("/pdf/accessibility/weblinks.pdf")); + WebContents* guest_contents = LoadPdfGetGuestContents(url); + ASSERT_TRUE(guest_contents); + WaitForAccessibilityTreeToContainNodeWithName(guest_contents, "Page 1"); + + // Find the specific link node. + content::FindAccessibilityNodeCriteria find_criteria; + find_criteria.role = ax::mojom::Role::kLink; + find_criteria.name = "http://bing.com"; + content::TestBrowserAccessibility* link_node = + content::FindAccessibilityNode(guest_contents, find_criteria); + ASSERT_TRUE(link_node); + + // Invoke action on a link and wait for navigation to complete. + content::AccessibilityNotificationWaiter event_waiter( + GetActiveWebContents(), ui::kAXModeComplete, + ax::mojom::Event::kLoadComplete); + ui::AXActionData action_data; + action_data.action = ax::mojom::Action::kDoDefault; + action_data.target_node_id = link_node->GetData().id; + link_node->AccessibilityPerformAction(action_data); + event_waiter.WaitForNotification(); + + // Test that navigation occurred correctly. + const GURL& expected_url = GetActiveWebContents()->GetURL(); + EXPECT_EQ("https://bing.com/", expected_url.spec()); +}
diff --git a/chrome/browser/plugins/plugin_info_host_impl.cc b/chrome/browser/plugins/plugin_info_host_impl.cc index 865ca928..d49a1df 100644 --- a/chrome/browser/plugins/plugin_info_host_impl.cc +++ b/chrome/browser/plugins/plugin_info_host_impl.cc
@@ -40,7 +40,6 @@ #include "components/nacl/common/buildflags.h" #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" -#include "components/rappor/rappor_service_impl.h" #include "components/ukm/content/source_url_recorder.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/plugin_service.h" @@ -412,7 +411,7 @@ context_.MaybeGrantAccess(output->status, output->plugin.path); if (output->status != chrome::mojom::PluginStatus::kNotFound) { - ReportMetrics(params.render_frame_id, output->actual_mime_type, params.url, + ReportMetrics(params.render_frame_id, output->actual_mime_type, params.main_frame_origin); } std::move(callback).Run(std::move(output)); @@ -420,7 +419,6 @@ void PluginInfoHostImpl::ReportMetrics(int render_frame_id, const base::StringPiece& mime_type, - const GURL& url, const url::Origin& main_frame_origin) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -435,10 +433,6 @@ if (web_contents->GetBrowserContext()->IsOffTheRecord()) return; - rappor::RapporServiceImpl* rappor_service = - g_browser_process->rappor_service(); - if (!rappor_service) - return; if (main_frame_origin.opaque()) return; @@ -447,16 +441,6 @@ return; } - rappor_service->RecordSampleString( - "Plugins.FlashOriginUrl", rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, - net::registry_controlled_domains::GetDomainAndRegistry( - main_frame_origin.GetURL(), - net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); - rappor_service->RecordSampleString( - "Plugins.FlashUrl", rappor::ETLD_PLUS_ONE_RAPPOR_TYPE, - net::registry_controlled_domains::GetDomainAndRegistry( - url, net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)); - ukm::builders::Plugins_FlashInstance( ukm::GetSourceIdForWebContentsDocument(web_contents)) .Record(ukm::UkmRecorder::Get());
diff --git a/chrome/browser/plugins/plugin_info_host_impl.h b/chrome/browser/plugins/plugin_info_host_impl.h index 33c692ea..cd0de67 100644 --- a/chrome/browser/plugins/plugin_info_host_impl.h +++ b/chrome/browser/plugins/plugin_info_host_impl.h
@@ -130,10 +130,9 @@ GetPluginInfoCallback callback, std::unique_ptr<PluginMetadata> plugin_metadata); - // Reports usage metrics to RAPPOR and UKM. + // Reports usage metrics to UKM. void ReportMetrics(int render_frame_id, const base::StringPiece& mime_type, - const GURL& url, const url::Origin& main_frame_origin); Context context_;
diff --git a/chrome/browser/preferences/BUILD.gn b/chrome/browser/preferences/BUILD.gn index 9de8dd6d..5b3a39c8 100644 --- a/chrome/browser/preferences/BUILD.gn +++ b/chrome/browser/preferences/BUILD.gn
@@ -5,7 +5,10 @@ import("//build/config/android/rules.gni") android_library("java") { - java_files = [ "android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java" ] + java_files = [ + "android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java", + "android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java", + ] deps = [ "//base:base_java", ]
diff --git a/chrome/browser/preferences/OWNERS b/chrome/browser/preferences/OWNERS index 6885464..1fa5c33 100644 --- a/chrome/browser/preferences/OWNERS +++ b/chrome/browser/preferences/OWNERS
@@ -1,2 +1,6 @@ chouinard@chromium.org hnakashima@chromium.org + +per-file *ChromePreferenceKeys.java=* + +# COMPONENT: Internals>Preferences
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java new file mode 100644 index 0000000..8e7580be --- /dev/null +++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -0,0 +1,102 @@ +// 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.preferences; + +/** + * Contains String constants with the SharedPreferences keys used by Chrome. + * + * All Chrome layer SharedPreferences keys should be added here. + * + * Do not remove constants from here. Keys that were used in past versions but are not used anymore + * cannot be reused. Mark them as @Deprecated. + * + * TODO(crbug.com/1022107): Finish moving constants from ChromePreferenceManager. + * TODO(crbug.com/1013781): Implement key deprecation. For now, just mark them as @Deprecated. + */ +public final class ChromePreferenceKeys { + /** An all-time counter of taps that triggered the Contextual Search peeking panel. */ + public static final String CONTEXTUAL_SEARCH_ALL_TIME_TAP_COUNT = + "contextual_search_all_time_tap_count"; + /** An all-time counter of Contextual Search panel opens triggered by any gesture.*/ + public static final String CONTEXTUAL_SEARCH_ALL_TIME_OPEN_COUNT = + "contextual_search_all_time_open_count"; + /** + * The number of times a tap gesture caused a Contextual Search Quick Answer to be shown. + * Cumulative, starting at M-69. + */ + public static final String CONTEXTUAL_SEARCH_ALL_TIME_TAP_QUICK_ANSWER_COUNT = + "contextual_search_all_time_tap_quick_answer_count"; + /** + * The number of times that a tap triggered the Contextual Search panel to peek since the last + * time the panel was opened. Note legacy string value without "open". + */ + public static final String CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT = + "contextual_search_tap_count"; + /** + * The number of times a tap gesture caused a Contextual Search Quick Answer to be shown since + * the last time the panel was opened. Note legacy string value without "open". + */ + public static final String CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_QUICK_ANSWER_COUNT = + "contextual_search_tap_quick_answer_count"; + /** + * The number of times the Contextual Search panel was opened with the opt-in promo visible. + */ + public static final String CONTEXTUAL_SEARCH_PROMO_OPEN_COUNT = + "contextual_search_promo_open_count"; + /** + * The entity-data impressions count for Contextual Search, i.e. thumbnails shown in the Bar. + * Cumulative, starting at M-69. + */ + public static final String CONTEXTUAL_SEARCH_ENTITY_IMPRESSIONS_COUNT = + "contextual_search_entity_impressions_count"; + /** + * The entity-data opens count for Contextual Search, e.g. Panel opens following thumbnails + * shown in the Bar. Cumulative, starting at M-69. + */ + public static final String CONTEXTUAL_SEARCH_ENTITY_OPENS_COUNT = + "contextual_search_entity_opens_count"; + /** + * The Quick Action impressions count for Contextual Search, i.e. actions presented in the Bar. + * Cumulative, starting at M-69. + */ + public static final String CONTEXTUAL_SEARCH_QUICK_ACTION_IMPRESSIONS_COUNT = + "contextual_search_quick_action_impressions_count"; + /** + * The Quick Actions taken count for Contextual Search, i.e. phone numbers dialed and similar + * actions. Cumulative, starting at M-69. + */ + public static final String CONTEXTUAL_SEARCH_QUICK_ACTIONS_TAKEN_COUNT = + "contextual_search_quick_actions_taken_count"; + /** + * The Quick Actions ignored count, i.e. phone numbers available but not dialed. + * Cumulative, starting at M-69. + */ + public static final String CONTEXTUAL_SEARCH_QUICK_ACTIONS_IGNORED_COUNT = + "contextual_search_quick_actions_ignored_count"; + /** + * A user interaction event ID for interaction with Contextual Search, stored as a long. + */ + public static final String CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_EVENT_ID = + "contextual_search_previous_interaction_event_id"; + /** + * An encoded set of outcomes of user interaction with Contextual Search, stored as an int. + */ + public static final String CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_ENCODED_OUTCOMES = + "contextual_search_previous_interaction_encoded_outcomes"; + /** + * A timestamp indicating when we updated the user interaction with Contextual Search, stored + * as a long, with resolution in days. + */ + public static final String CONTEXTUAL_SEARCH_PREVIOUS_INTERACTION_TIMESTAMP = + "contextual_search_previous_interaction_timestamp"; + public static final String CONTEXTUAL_SEARCH_TAP_TRIGGERED_PROMO_COUNT = + "contextual_search_tap_triggered_promo_count"; + public static final String CONTEXTUAL_SEARCH_LAST_ANIMATION_TIME = + "contextual_search_last_animation_time"; + public static final String CONTEXTUAL_SEARCH_CURRENT_WEEK_NUMBER = + "contextual_search_current_week_number"; + + private ChromePreferenceKeys() {} +}
diff --git a/chrome/browser/themes/browser_theme_pack.cc b/chrome/browser/themes/browser_theme_pack.cc index 91f6610..eec91acb 100644 --- a/chrome/browser/themes/browser_theme_pack.cc +++ b/chrome/browser/themes/browser_theme_pack.cc
@@ -24,6 +24,7 @@ #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/themes/theme_properties.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/frame/window_frame_util.h" #include "chrome/common/extensions/manifest_handlers/theme_handler.h" #include "chrome/common/themes/autogenerated_theme_util.h" @@ -31,7 +32,10 @@ #include "components/crx_file/id_util.h" #include "content/public/browser/browser_thread.h" #include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/base/resource/data_pack.h" +#include "ui/color/color_mixer.h" +#include "ui/color/color_provider.h" #include "ui/gfx/canvas.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/color_analysis.h" @@ -1011,6 +1015,29 @@ return false; } +void BrowserThemePack::AddCustomThemeColorMixers( + ui::ColorProvider* provider) const { + // A map from theme property IDs to color IDs for use in color mixers. + constexpr struct { + int property_id; + int color_id; + } kThemePropertiesMap[] = { + {TP::COLOR_TOOLBAR, kColorToolbar}, + {TP::COLOR_OMNIBOX_TEXT, kColorOmniboxText}, + {TP::COLOR_OMNIBOX_BACKGROUND, kColorOmniboxBackground}, + }; + + ui::ColorSet::ColorMap theme_colors; + SkColor color; + for (const auto& entry : kThemePropertiesMap) { + if (GetColor(entry.property_id, &color)) + theme_colors.insert({entry.color_id, color}); + } + if (theme_colors.empty()) + return; + provider->AddMixer()->AddSet({kColorSetCustomTheme, std::move(theme_colors)}); +} + // private: void BrowserThemePack::AdjustThemePack() {
diff --git a/chrome/browser/themes/browser_theme_pack.h b/chrome/browser/themes/browser_theme_pack.h index f578388..86fc5a0 100644 --- a/chrome/browser/themes/browser_theme_pack.h +++ b/chrome/browser/themes/browser_theme_pack.h
@@ -31,6 +31,7 @@ } namespace ui { +class ColorProvider; class DataPack; } @@ -94,6 +95,10 @@ const override; bool HasCustomImage(int id) const override; + // Builds the color mixers that represent the state of the current browser + // theme instance. + void AddCustomThemeColorMixers(ui::ColorProvider* provider) const; + private: friend class BrowserThemePackTest;
diff --git a/chrome/browser/themes/browser_theme_pack_unittest.cc b/chrome/browser/themes/browser_theme_pack_unittest.cc index cf5748f..f315f5c 100644 --- a/chrome/browser/themes/browser_theme_pack_unittest.cc +++ b/chrome/browser/themes/browser_theme_pack_unittest.cc
@@ -13,12 +13,16 @@ #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/themes/theme_properties.h" +#include "chrome/browser/ui/color/chrome_color_id.h" #include "chrome/browser/ui/frame/window_frame_util.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/themes/autogenerated_theme_util.h" #include "chrome/grit/theme_resources.h" #include "content/public/test/browser_task_environment.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/color/color_mixer.h" +#include "ui/color/color_provider.h" +#include "ui/color/color_test_ids.h" #include "ui/gfx/color_utils.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" @@ -733,6 +737,56 @@ EXPECT_FALSE(LoadRawBitmapsTo(out_file_paths)); } +TEST_F(BrowserThemePackTest, TestCreateColorMixersOmniboxNoValues) { + // Tests to make sure that existing colors within the color provider are not + // overwritten or lost in the absence of any user provided theme values. + ui::ColorProvider provider; + provider.AddMixer()->AddSet({ui::kColorSetTest0, + {{kColorToolbar, SK_ColorRED}, + {kColorOmniboxText, SK_ColorGREEN}, + {kColorOmniboxBackground, SK_ColorBLUE}}}); + theme_pack().AddCustomThemeColorMixers(&provider); + EXPECT_EQ(SK_ColorRED, provider.GetColor(kColorToolbar)); + EXPECT_EQ(SK_ColorGREEN, provider.GetColor(kColorOmniboxText)); + EXPECT_EQ(SK_ColorBLUE, provider.GetColor(kColorOmniboxBackground)); +} + +TEST_F(BrowserThemePackTest, TestCreateColorMixersOmniboxPartialValues) { + // Tests to make sure that only provided theme values are replicated into the + // color provider. + ui::ColorProvider provider; + provider.AddMixer()->AddSet({ui::kColorSetTest0, + {{kColorToolbar, SK_ColorRED}, + {kColorOmniboxText, SK_ColorGREEN}, + {kColorOmniboxBackground, SK_ColorBLUE}}}); + std::string color_json = R"({ "toolbar": [0, 20, 40], + "omnibox_text": [60, 80, 100] })"; + LoadColorJSON(color_json); + theme_pack().AddCustomThemeColorMixers(&provider); + EXPECT_EQ(SkColorSetRGB(0, 20, 40), provider.GetColor(kColorToolbar)); + EXPECT_EQ(SkColorSetRGB(60, 80, 100), provider.GetColor(kColorOmniboxText)); + EXPECT_EQ(SK_ColorBLUE, provider.GetColor(kColorOmniboxBackground)); +} + +TEST_F(BrowserThemePackTest, TestCreateColorMixersOmniboxAllValues) { + // Tests to make sure that all available colors are properly loaded into the + // color provider. + ui::ColorProvider provider; + provider.AddMixer()->AddSet({ui::kColorSetTest0, + {{kColorToolbar, SK_ColorRED}, + {kColorOmniboxText, SK_ColorGREEN}, + {kColorOmniboxBackground, SK_ColorBLUE}}}); + std::string color_json = R"({ "toolbar": [0, 20, 40], + "omnibox_text": [60, 80, 100], + "omnibox_background": [120, 140, 160] })"; + LoadColorJSON(color_json); + theme_pack().AddCustomThemeColorMixers(&provider); + EXPECT_EQ(SkColorSetRGB(0, 20, 40), provider.GetColor(kColorToolbar)); + EXPECT_EQ(SkColorSetRGB(60, 80, 100), provider.GetColor(kColorOmniboxText)); + EXPECT_EQ(SkColorSetRGB(120, 140, 160), + provider.GetColor(kColorOmniboxBackground)); +} + // TODO(erg): This test should actually test more of the built resources from // the extension data, but for now, exists so valgrind can test some of the // tricky memory stuff that BrowserThemePack does.
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.cc index b92e536f..e5a1e996 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.cc
@@ -4,172 +4,23 @@ #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.h" -#include "base/bind.h" -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/important_file_writer.h" -#include "base/guid.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/stl_util.h" -#include "base/strings/string_number_conversions.h" -#include "base/task/post_task.h" -#include "base/threading/scoped_blocking_call.h" -#include "base/time/time.h" -#include "base/unguessable_token.h" -#include "chrome/browser/profiles/profile.h" -#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder_state.pb.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder_util.h" -#include "components/metrics/metrics_log.h" -#include "crypto/sha2.h" -#include "third_party/metrics_proto/chrome_os_app_list_launch_event.pb.h" -#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" namespace app_list { namespace { -using ::metrics::ChromeOSAppListLaunchEventProto; using ::metrics::ChromeUserMetricsExtension; -using ::metrics::MetricsLog; - -// Length of the user secret string, in bytes. -constexpr size_t kSecretSize = 32; - -// Tries to serialize the given AppListLaunchRecorderStateProto to disk at the -// given |filepath|. -void SaveStateToDisk(const base::FilePath& filepath, - const AppListLaunchRecorderStateProto& proto) { - std::string proto_str; - if (!proto.SerializeToString(&proto_str)) { - LOG(DFATAL) << "Error serializing AppListLaunchRecorderStateProto."; - LogMetricsProviderError(MetricsProviderError::kStateToProtoError); - return; - } - - bool write_result = false; - { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); - write_result = base::ImportantFileWriter::WriteFileAtomically( - filepath, proto_str, "AppListLaunchMetricsProvider"); - } - - if (!write_result) { - LOG(DFATAL) << "Error writing AppListLaunchRecorderStateProto."; - LogMetricsProviderError(MetricsProviderError::kStateWriteError); - } -} - -// Tries to load an |AppListLaunchRecorderStateProto| from the given filepath. -// If it fails, returns nullopt. -base::Optional<AppListLaunchRecorderStateProto> LoadStateFromDisk( - const base::FilePath& filepath) { - std::string proto_str; - { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); - // If the state file doesn't exist, it's not necessarily an error: this may - // be the first time the provider is being run. - if (!base::PathExists(filepath)) - return base::nullopt; - - if (!base::ReadFileToString(filepath, &proto_str)) { - LOG(DFATAL) << "Error reading AppListLaunchRecorderStateProto."; - LogMetricsProviderError(MetricsProviderError::kStateReadError); - return base::nullopt; - } - } - - AppListLaunchRecorderStateProto proto; - if (!proto.ParseFromString(proto_str)) { - LOG(DFATAL) << "Error parsing AppListLaunchRecorderStateProto."; - LogMetricsProviderError(MetricsProviderError::kStateFromProtoError); - return base::nullopt; - } - - return proto; -} - -// Returns the file path of the primary user's profile, if it exists and is not -// a guest session or system profile. Otherwise, returns base::nullopt. -base::Optional<base::FilePath> GetProfileDir() { - // We do not handle multiprofile, events from all logged-in profiles are - // logged under the primary user. - Profile* profile = ProfileManager::GetPrimaryUserProfile(); - // Only enable if the current profile is a regular profile, not a guest - // session or the login screen. - if (!profile || profile->IsGuestSession() || profile->IsSystemProfile()) - return base::nullopt; - return profile->GetPath(); -} - -// Generates a cryptographically secure random secret of size |kSecretSize|. -Secret GenerateSecret() { - const auto secret = base::UnguessableToken::Create().ToString(); - DCHECK_EQ(secret.size(), kSecretSize); - return {secret}; -} - -// Generates a random user ID. -uint64_t GenerateUserID() { - // This is analogous to how the UMA client ID is generated in - // metrics::MetricsStateManager. - return MetricsLog::Hash(base::GenerateGUID()); -} - -// Generates a proto containing a new secret and user ID. -AppListLaunchRecorderStateProto GenerateStateProto() { - AppListLaunchRecorderStateProto proto; - proto.set_secret(GenerateSecret().value); - proto.set_recurrence_ranker_user_id(GenerateUserID()); - return proto; -} - -// Returns the user secret stored in |proto|. -Secret GetSecretFromProto(const AppListLaunchRecorderStateProto& proto) { - DCHECK(proto.has_secret() && !proto.secret().empty()); - return {proto.secret()}; -} - -// Returns the first 8 bytes of the SHA256 hash of |secret| concatenated with -// |value|. -uint64_t HashWithSecret(const std::string& value, const Secret& secret) { - DCHECK(!secret.value.empty()); - uint64_t hash; - crypto::SHA256HashString(secret.value + value, &hash, sizeof(uint64_t)); - return hash; -} } // namespace int AppListLaunchMetricsProvider::kMaxEventsPerUpload = 100; -char AppListLaunchMetricsProvider::kStateProtoFilename[] = - "app_list_launch_recorder_state.pb"; -AppListLaunchMetricsProvider::AppListLaunchMetricsProvider( - base::RepeatingCallback<base::Optional<base::FilePath>()> - get_profile_dir_callback) - : get_profile_dir_callback_(get_profile_dir_callback), - init_state_(InitState::DISABLED), - secret_(base::nullopt), - user_id_(base::nullopt) {} - -AppListLaunchMetricsProvider::AppListLaunchMetricsProvider() - : AppListLaunchMetricsProvider(base::BindRepeating(GetProfileDir)) {} - +AppListLaunchMetricsProvider::AppListLaunchMetricsProvider() = default; AppListLaunchMetricsProvider::~AppListLaunchMetricsProvider() = default; void AppListLaunchMetricsProvider::OnRecordingEnabled() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - // We do not perform actual initialization or set to InitState::ENABLED here. - // Initialization must occur after the browser thread has finished - // initializing, which may not be the case when OnRecordingEnabled is - // called. Instead, initialization happens on the first call to - // OnAppListLaunch. - init_state_ = InitState::UNINITIALIZED; - subscription_ = AppListLaunchRecorder::GetInstance()->RegisterCallback( base::BindRepeating(&AppListLaunchMetricsProvider::OnAppListLaunch, weak_factory_.GetWeakPtr())); @@ -177,116 +28,20 @@ void AppListLaunchMetricsProvider::OnRecordingDisabled() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - init_state_ = InitState::DISABLED; - launch_info_cache_.clear(); - secret_.reset(); - user_id_.reset(); subscription_.reset(); } void AppListLaunchMetricsProvider::Initialize() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - - const auto& profile_dir = get_profile_dir_callback_.Run(); - if (!profile_dir) { - OnRecordingDisabled(); - return; - } - const base::FilePath& proto_filepath = profile_dir.value().AppendASCII( - AppListLaunchMetricsProvider::kStateProtoFilename); - - PostTaskAndReplyWithResult( - FROM_HERE, {base::ThreadPool(), base::MayBlock()}, - base::BindOnce(&LoadStateFromDisk, proto_filepath), - base::BindOnce(&AppListLaunchMetricsProvider::OnStateLoaded, - weak_factory_.GetWeakPtr(), proto_filepath)); -} - -void AppListLaunchMetricsProvider::OnStateLoaded( - const base::FilePath& proto_filepath, - const base::Optional<AppListLaunchRecorderStateProto>& proto) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (proto) { - secret_ = GetSecretFromProto(proto.value()); - user_id_ = proto.value().recurrence_ranker_user_id(); - } else { - // Either there is no state proto saved, or it was corrupt. Generate a new - // secret and ID regardless. We log an 'error' to UMA despite this not - // always being an error, because this happening too frequently would - // indicate an issue with the system. - LogMetricsProviderError(MetricsProviderError::kNoStateProto); - - AppListLaunchRecorderStateProto new_proto = GenerateStateProto(); - PostTask(FROM_HERE, {base::ThreadPool(), base::MayBlock()}, - base::BindOnce(&SaveStateToDisk, proto_filepath, new_proto)); - - secret_ = GetSecretFromProto(new_proto); - user_id_ = new_proto.recurrence_ranker_user_id(); - } - - if (!user_id_) { - LogMetricsProviderError(MetricsProviderError::kInvalidUserId); - OnRecordingDisabled(); - } else if (!secret_ || secret_.value().value.size() != kSecretSize) { - LogMetricsProviderError(MetricsProviderError::kInvalidSecret); - OnRecordingDisabled(); - } else { - init_state_ = InitState::ENABLED; - } } void AppListLaunchMetricsProvider::ProvideCurrentSessionData( ChromeUserMetricsExtension* uma_proto) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (init_state_ == InitState::ENABLED) { - for (const auto& launch_info : launch_info_cache_) { - CreateLaunchEvent(launch_info, - uma_proto->add_chrome_os_app_list_launch_event()); - } - launch_info_cache_.clear(); - } } void AppListLaunchMetricsProvider::OnAppListLaunch( const AppListLaunchRecorder::LaunchInfo& launch_info) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (init_state_ == InitState::UNINITIALIZED) { - init_state_ = InitState::INIT_STARTED; - Initialize(); - } - - if (init_state_ == InitState::DISABLED || - launch_info_cache_.size() >= static_cast<size_t>(kMaxEventsPerUpload)) - return; - - if (launch_info.client == AppListLaunchRecorder::Client::kUnspecified) { - LogMetricsProviderError(MetricsProviderError::kLaunchTypeUnspecified); - return; - } - - launch_info_cache_.push_back(launch_info); - - // We want the metric to reflect the number of uploads affected, not the - // number of dropped events, so only log an error when max events is first - // exceeded. - if (launch_info_cache_.size() == static_cast<size_t>(kMaxEventsPerUpload)) - LogMetricsProviderError(MetricsProviderError::kMaxEventsPerUploadExceeded); -} - -void AppListLaunchMetricsProvider::CreateLaunchEvent( - const AppListLaunchRecorder::LaunchInfo& launch_info, - ChromeOSAppListLaunchEventProto* event) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(secret_ && user_id_); - - base::Time::Exploded now; - base::Time::Now().LocalExplode(&now); - - // TODO(crbug.com/1016655): set hashed and unhashed data after proto has been - // updated. - - // Dummy call so that HashWithSecret compiles. - LOG(ERROR) << HashWithSecret("dummy hash", secret_.value()); } } // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.h b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.h index cd8e694..8801533 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.h +++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider.h
@@ -25,14 +25,7 @@ namespace app_list { -// Stores a user's random secret. This struct exists to make clear at the type -// system level what is a secret and what isn't. -struct Secret { - std::string value; -}; - class AppListLaunchMetricsProviderTest; -class AppListLaunchRecorderStateProto; // AppListLaunchMetricsProvider is responsible for filling out the // |app_list_launch_event| section of the UMA proto. This class should not be @@ -51,76 +44,28 @@ private: friend class ::ChromeMetricsServiceClient; friend class app_list::AppListLaunchMetricsProviderTest; - FRIEND_TEST_ALL_PREFIXES(AppListLaunchMetricsProviderTest, EventsAreCapped); - - // Filename for the the state proto within the user's home directory. This is - // just the basename, not the full path. - static char kStateProtoFilename[]; // Beyond this number of OnAppListLaunch calls between successive calls to // ProvideCurrentSessionData, we stop logging. static int kMaxEventsPerUpload; - enum class InitState { UNINITIALIZED, INIT_STARTED, ENABLED, DISABLED }; - // The constructors are private so that this class can only be instantied by - // ChromeMetricsServiceClient and tests. The class has two constructors so - // that the tests can override the profile dir. + // ChromeMetricsServiceClient and tests. AppListLaunchMetricsProvider(); - AppListLaunchMetricsProvider( - base::RepeatingCallback<base::Optional<base::FilePath>()> - get_profile_dir_callback); - // Records the information in |launch_info|, to be converted into a hashed // form and logged to UMA. Actual logging occurs periodically, so it is not // guaranteed that any call to this method will be logged. // - // OnAppListLaunch should only be called from the browser thread, after it has - // finished initializing. + // OnAppListLaunch should only be called from the browser UI sequence. void OnAppListLaunch(const AppListLaunchRecorder::LaunchInfo& launch_info); - // Starts initialization if needed. This involves reading the secret from - // disk. + // Performs initialization once a user has logged in. void Initialize(); - // Populates this object's internal state from the given state |proto|, and - // finishes initialisation. This is called by Initialize() and passed the - // state proto that has been loaded from disk, if it exists. OnStateLoaded may - // write a new proto to disk if, for example, the given |proto| is invalid. - void OnStateLoaded( - const base::FilePath& proto_filepath, - const base::Optional<AppListLaunchRecorderStateProto>& proto); - - // Converts |launch_info| into a hashed |event| proto ready for logging. - void CreateLaunchEvent(const AppListLaunchRecorder::LaunchInfo& launch_info, - metrics::ChromeOSAppListLaunchEventProto* event); - - // A function that returns the directory of the current profile. This is a - // callback so that it can be faked out for testing. - const base::RepeatingCallback<base::Optional<base::FilePath>()> - get_profile_dir_callback_; - // Subscription for receiving logging event callbacks from HashedLogger. std::unique_ptr<AppListLaunchRecorder::LaunchEventSubscription> subscription_; - // Cache of input launch data, to be hashed and returned when - // ProvideCurrentSessionData() is called. - std::vector<AppListLaunchRecorder::LaunchInfo> launch_info_cache_; - - // The initialization state of the AppListLaunchMetricsProvider. Events are - // only provided on a call to ProvideCurrentSessionData() once this is - // enabled, and nothing is recorded if this is disabled. - InitState init_state_; - - // Secret per-user salt concatenated with values before hashing. Serialized - // to disk. - base::Optional<Secret> secret_; - - // Per-user per-client ID used only for AppListLaunchMetricsProvider. - // Serialized to disk. - base::Optional<uint64_t> user_id_; - SEQUENCE_CHECKER(sequence_checker_); base::WeakPtrFactory<AppListLaunchMetricsProvider> weak_factory_{this};
diff --git a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider_unittest.cc b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider_unittest.cc index 33b6e5dd..065f62305 100644 --- a/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider_unittest.cc +++ b/chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_metrics_provider_unittest.cc
@@ -21,7 +21,6 @@ #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder.h" -#include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder_state.pb.h" #include "chrome/browser/ui/app_list/search/search_result_ranker/app_list_launch_recorder_util.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -31,7 +30,6 @@ #include "content/public/test/browser_task_environment.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#include "third_party/metrics_proto/chrome_os_app_list_launch_event.pb.h" #include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" #include "third_party/protobuf/src/google/protobuf/repeated_field.h" @@ -40,44 +38,6 @@ namespace { using ::chromeos::ProfileHelper; -using ::metrics::ChromeOSAppListLaunchEventProto; - -// 32 bytes long, matching the size of a real secret. -constexpr char kSecret[] = "abcdefghijklmnopqrstuvwxyzabcdef"; - -constexpr uint64_t kUserId = 1123u; - -constexpr char kValue1[] = "value one"; -constexpr char kValue2[] = "value two"; -constexpr char kValue3[] = "value three"; -constexpr char kValue4[] = "value four"; - -// These are hex encoded values of the first 8 bytes of sha256(kSecret + -// kValueN), generated with the sha256sum command. These are hex encoded to make -// debugging incorrect values easier. -constexpr char kValue1Hash[] = "E79C24CD2117A2BB"; -constexpr char kValue2Hash[] = "506ECDDC0BA3C341"; -constexpr char kValue3Hash[] = "1E0CDC361557A12F"; -constexpr char kValue4Hash[] = "4875030730DE902A"; - -enum class TestEvent { - kValueA = 0, - kValueB = 1, - kValueC = 2, -}; - -std::string HashToHex(uint64_t hash) { - return base::HexEncode(&hash, sizeof(uint64_t)); -} - -void ExpectLoggingEventEquals(ChromeOSAppListLaunchEventProto proto, - std::string value_a, - std::string value_b, - int value_c) { - // TODO(crbug.com/1016655): reimplement once proto has been refactored. - // Dummy call so HashToHex compiles. - LOG(ERROR) << HashToHex(0u); -} } // namespace @@ -87,119 +47,6 @@ base::Optional<base::FilePath> GetTempDir() { return temp_dir_.GetPath(); } - void MakeProvider() { - // Using WrapUnique to access a private constructor. - provider_ = base::WrapUnique(new AppListLaunchMetricsProvider( - base::BindRepeating(&AppListLaunchMetricsProviderTest::GetTempDir, - base::Unretained(this)))); - provider_->OnRecordingEnabled(); - } - - void InitProvider() { - AddLog("", "", 0); - Wait(); - } - - void ExpectUninitialized() { - EXPECT_EQ(AppListLaunchMetricsProvider::InitState::UNINITIALIZED, - provider_->init_state_); - } - - void ExpectInitStarted() { - EXPECT_EQ(AppListLaunchMetricsProvider::InitState::INIT_STARTED, - provider_->init_state_); - } - - void ExpectEnabled() { - EXPECT_EQ(AppListLaunchMetricsProvider::InitState::ENABLED, - provider_->init_state_); - } - - void ExpectDisabled() { - EXPECT_EQ(AppListLaunchMetricsProvider::InitState::DISABLED, - provider_->init_state_); - } - - base::Optional<Secret> GetSecret() { return provider_->secret_; } - - std::string ReadSecret() { - std::string proto_str; - { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); - - base::FilePath path = temp_dir_.GetPath().AppendASCII( - AppListLaunchMetricsProvider::kStateProtoFilename); - CHECK(base::ReadFileToString(path, &proto_str)); - } - - auto proto = std::make_unique<AppListLaunchRecorderStateProto>(); - CHECK(proto->ParseFromString(proto_str)); - return proto->secret(); - } - - uint64_t ReadUserId() { - std::string proto_str; - { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); - - base::FilePath path = temp_dir_.GetPath().AppendASCII( - AppListLaunchMetricsProvider::kStateProtoFilename); - CHECK(base::ReadFileToString(path, &proto_str)); - } - - auto proto = std::make_unique<AppListLaunchRecorderStateProto>(); - CHECK(proto->ParseFromString(proto_str)); - return proto->recurrence_ranker_user_id(); - } - - void WriteStateProto(const std::string& secret) { - AppListLaunchRecorderStateProto proto; - proto.set_recurrence_ranker_user_id(kUserId); - proto.set_secret(secret); - - std::string proto_str; - CHECK(proto.SerializeToString(&proto_str)); - { - base::ScopedBlockingCall scoped_blocking_call( - FROM_HERE, base::BlockingType::MAY_BLOCK); - CHECK(base::ImportantFileWriter::WriteFileAtomically( - temp_dir_.GetPath().AppendASCII( - AppListLaunchMetricsProvider::kStateProtoFilename), - proto_str, "AppListLaunchMetricsProviderTest")); - } - - Wait(); - } - - void DeleteStateProto() { - DeleteFile(temp_dir_.GetPath().AppendASCII( - AppListLaunchMetricsProvider::kStateProtoFilename), - false); - } - - void AddLog(std::string value_a, std::string value_b, int value_c) { - AppListLaunchRecorder::LaunchInfo event; - event.client = AppListLaunchRecorder::Client::kTesting; - event.hashed = {{static_cast<int>(TestEvent::kValueA), value_a}, - {static_cast<int>(TestEvent::kValueB), value_b}}; - event.unhashed = {{static_cast<int>(TestEvent::kValueC), value_c}}; - - provider_->OnAppListLaunch(event); - } - - google::protobuf::RepeatedPtrField<ChromeOSAppListLaunchEventProto> - GetLogs() { - metrics::ChromeUserMetricsExtension uma_log; - provider_->ProvideCurrentSessionData(&uma_log); - return uma_log.chrome_os_app_list_launch_event(); - } - - void ExpectNoErrors() { - histogram_tester_.ExpectTotalCount("Apps.AppListLaunchRecorderError", 0); - } - void Wait() { task_environment_.RunUntilIdle(); } base::HistogramTester histogram_tester_; @@ -209,166 +56,4 @@ std::unique_ptr<AppListLaunchMetricsProvider> provider_; }; -TEST_F(AppListLaunchMetricsProviderTest, - DISABLED_ProvidesNothingWhenUninitialized) { - MakeProvider(); - - ExpectUninitialized(); - EXPECT_TRUE(GetLogs().empty()); - ExpectNoErrors(); -} - -TEST_F(AppListLaunchMetricsProviderTest, DISABLED_SucceedsGeneratingNewSecret) { - MakeProvider(); - InitProvider(); - - ExpectEnabled(); - // Because the secret is random, we settle for just checking its length. - // In the object: - EXPECT_EQ(32ul, GetSecret().value().value.size()); - // On disk: - EXPECT_EQ(32ul, ReadSecret().size()); - - EXPECT_EQ(GetSecret().value().value, ReadSecret()); - - histogram_tester_.ExpectUniqueSample("Apps.AppListLaunchRecorderError", - MetricsProviderError::kNoStateProto, 1); -} - -TEST_F(AppListLaunchMetricsProviderTest, - DISABLED_SucceedsLoadingExistingSecret) { - WriteStateProto(kSecret); - - MakeProvider(); - InitProvider(); - - ExpectEnabled(); - EXPECT_EQ(kSecret, GetSecret().value().value); - ExpectNoErrors(); -} - -TEST_F(AppListLaunchMetricsProviderTest, DISABLED_DisableOnInvalidSecret) { - WriteStateProto("wrong length"); - - MakeProvider(); - InitProvider(); - - ExpectDisabled(); - histogram_tester_.ExpectUniqueSample("Apps.AppListLaunchRecorderError", - MetricsProviderError::kInvalidSecret, 1); -} - -// Tests that a call to ProvideCurrentSessionData populates protos for each log, -// and that those protos contain the right values. -TEST_F(AppListLaunchMetricsProviderTest, DISABLED_CorrectHashedValues) { - WriteStateProto(kSecret); - MakeProvider(); - InitProvider(); - - AddLog(kValue1, kValue2, 5); - AddLog(kValue2, kValue3, 7); - AddLog(kValue3, kValue4, 9); - - const auto& events = GetLogs(); - // events[0] is a dummy log created in |InitProvider|. We don't test for its - // contents below. - ASSERT_EQ(events.size(), 4); - - ExpectLoggingEventEquals(events[1], kValue1Hash, kValue2Hash, 5); - ExpectLoggingEventEquals(events[2], kValue2Hash, kValue3Hash, 7); - ExpectLoggingEventEquals(events[3], kValue3Hash, kValue4Hash, 9); - ExpectNoErrors(); -} - -// Tests that the logs reported in one call to ProvideCurrentSessionData do no -// appear in the next. -TEST_F(AppListLaunchMetricsProviderTest, DISABLED_EventsNotDuplicated) { - WriteStateProto(kSecret); - MakeProvider(); - InitProvider(); - - AddLog(kValue1, kValue2, 44); - auto events = GetLogs(); - ASSERT_EQ(events.size(), 2); - ExpectLoggingEventEquals(events[1], kValue1Hash, kValue2Hash, 44); - - AddLog(kValue1, kValue4, 22); - events = GetLogs(); - ASSERT_EQ(events.size(), 1); - ExpectLoggingEventEquals(events[0], kValue3Hash, kValue4Hash, 22); - - EXPECT_TRUE(GetLogs().empty()); - ExpectNoErrors(); -} - -// Tests that logging events are dropped after an unreasonably large number of -// them are made between uploads. -TEST_F(AppListLaunchMetricsProviderTest, DISABLED_EventsAreCapped) { - MakeProvider(); - InitProvider(); - - const int max_events = AppListLaunchMetricsProvider::kMaxEventsPerUpload; - - // Not enough events to hit the cap. - for (int i = 0; i < max_events / 2; ++i) - AddLog(kValue1, kValue2, 1); - // One event from init, kMaxEventsPerUpload/2 from the loop. - EXPECT_EQ(1 + max_events / 2, GetLogs().size()); - - // Enough events to hit the cap. - for (int i = 0; i < 2 * max_events; ++i) - AddLog(kValue1, kValue2, 1); - EXPECT_EQ(max_events, GetLogs().size()); - - histogram_tester_.ExpectBucketCount( - "Apps.AppListLaunchRecorderError", - MetricsProviderError::kMaxEventsPerUploadExceeded, 1); -} - -// Tests that logging events that occur before the provider is initialized are -// still correctly logged after initialization. -TEST_F(AppListLaunchMetricsProviderTest, - DISABLED_LaunchEventsBeforeInitializationAreRecorded) { - WriteStateProto(kSecret); - MakeProvider(); - - // To begin with, the provider is uninitialized and has no logs at all. - EXPECT_TRUE(GetLogs().empty()); - // These logs are added before the provider has finished initialising. - AddLog(kValue1, kValue2, 1); - AddLog(kValue2, kValue3, 2); - AddLog(kValue3, kValue4, 3); - // Initialisation is finished here. - Wait(); - - const auto& events = GetLogs(); - ASSERT_EQ(events.size(), 3); - ExpectLoggingEventEquals(events[0], kValue1Hash, kValue2Hash, 1); - ExpectLoggingEventEquals(events[1], kValue2Hash, kValue3Hash, 2); - ExpectLoggingEventEquals(events[2], kValue3Hash, kValue4Hash, 3); - - EXPECT_TRUE(GetLogs().empty()); - ExpectNoErrors(); -} - -// Without an existing saved state, instantiating a metrics provider should save -// an almost certainly unique user ID and secret. Test this by creating a few -// blank-slate metrics providers. -TEST_F(AppListLaunchMetricsProviderTest, DISABLED_UserIDsAndSecretsAreUnique) { - const int num_runs = 10; - - std::set<uint64_t> user_ids; - std::set<std::string> secrets; - for (int i = 0; i < num_runs; ++i) { - DeleteStateProto(); - MakeProvider(); - InitProvider(); - secrets.insert(ReadSecret()); - user_ids.insert(ReadUserId()); - } - - EXPECT_EQ(static_cast<size_t>(num_runs), secrets.size()); - EXPECT_EQ(static_cast<size_t>(num_runs), user_ids.size()); -} - } // namespace app_list
diff --git a/chrome/browser/ui/color/chrome_color_id.h b/chrome/browser/ui/color/chrome_color_id.h index b1a2efb..6b67962 100644 --- a/chrome/browser/ui/color/chrome_color_id.h +++ b/chrome/browser/ui/color/chrome_color_id.h
@@ -36,4 +36,8 @@ kColorToolbar, // TODO(pkasting): Add a recipe }; +enum ChromeColorSetIds : ui::ColorSetId { + kColorSetCustomTheme = ui::kUiColorSetsEnd, +}; + #endif // CHROME_BROWSER_UI_COLOR_CHROME_COLOR_ID_H_
diff --git a/chrome/browser/ui/libgtkui/gtk_event_loop_x11.cc b/chrome/browser/ui/libgtkui/gtk_event_loop_x11.cc index 5224e946..421e8a61 100644 --- a/chrome/browser/ui/libgtkui/gtk_event_loop_x11.cc +++ b/chrome/browser/ui/libgtkui/gtk_event_loop_x11.cc
@@ -18,15 +18,18 @@ namespace { -// Xkb Events stores group attribute into XKeyEvent::state bit field while -// GdkEventKey objects has separate fields for that purpose, they are ::state -// and ::group respectively. So recompose them when build XKeyEvent from -// GdkEventKey here. This is similar to XkbBuildCoreState(), but takes takes a -// uint instead of assuming a 8-bit Xkb state. +// Xkb Events store group attribute into XKeyEvent::state bit field, along with +// other state-related info, while GdkEventKey objects have separate fields for +// that purpose, they are ::state and ::group. This function is responsible for +// recomposing them into a single bit field value when translating GdkEventKey +// into XKeyEvent. This is similar to XkbBuildCoreState(), but assumes state is +// an uint rather than an uchar. // // More details: -// https://code.woboq.org/qt5/include/X11/extensions/XKB.h.html#_M/XkbBuildCoreState +// https://gitlab.freedesktop.org/xorg/proto/xorgproto/blob/master/include/X11/extensions/XKB.h#L372 int BuildXkbStateFromGdkEvent(const GdkEventKey& keyev) { + DCHECK_EQ(0u, XkbGroupForCoreState(keyev.state)); + DCHECK(XkbIsLegalGroup(keyev.group)); return keyev.state | ((keyev.group & 0x3) << 13); }
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc index abea74a..08ff0064 100644 --- a/chrome/browser/ui/page_info/page_info.cc +++ b/chrome/browser/ui/page_info/page_info.cc
@@ -130,6 +130,9 @@ ContentSettingsType::BACKGROUND_SYNC, ContentSettingsType::SOUND, ContentSettingsType::AUTOMATIC_DOWNLOADS, +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) + ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER, +#endif ContentSettingsType::AUTOPLAY, ContentSettingsType::MIDI_SYSEX, ContentSettingsType::CLIPBOARD_READ,
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc index 31d033c3..45425958 100644 --- a/chrome/browser/ui/page_info/page_info_ui.cc +++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -164,6 +164,10 @@ IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL}, {ContentSettingsType::MIDI_SYSEX, IDS_PAGE_INFO_TYPE_MIDI_SYSEX}, {ContentSettingsType::BACKGROUND_SYNC, IDS_PAGE_INFO_TYPE_BACKGROUND_SYNC}, +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) + {ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER, + IDS_PAGE_INFO_TYPE_PROTECTED_MEDIA_IDENTIFIER}, +#endif {ContentSettingsType::AUTOPLAY, IDS_PAGE_INFO_TYPE_AUTOPLAY}, {ContentSettingsType::ADS, IDS_PAGE_INFO_TYPE_ADS}, {ContentSettingsType::SOUND, IDS_PAGE_INFO_TYPE_SOUND}, @@ -583,6 +587,11 @@ case ContentSettingsType::AUTOMATIC_DOWNLOADS: icon = &kFileDownloadIcon; break; +#if defined(OS_CHROMEOS) + case ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER: + icon = &kProtectedContentIcon; + break; +#endif case ContentSettingsType::MIDI_SYSEX: icon = &vector_icons::kMidiIcon; break; @@ -604,11 +613,9 @@ case ContentSettingsType::USB_GUARD: icon = &vector_icons::kUsbIcon; break; -#if !defined(OS_ANDROID) case ContentSettingsType::SERIAL_GUARD: icon = &vector_icons::kSerialPortIcon; break; -#endif case ContentSettingsType::BLUETOOTH_SCANNING: icon = &vector_icons::kBluetoothScanningIcon; break;
diff --git a/chrome/browser/ui/page_info/page_info_ui.h b/chrome/browser/ui/page_info/page_info_ui.h index 8c55c7f..90619d77 100644 --- a/chrome/browser/ui/page_info/page_info_ui.h +++ b/chrome/browser/ui/page_info/page_info_ui.h
@@ -204,7 +204,7 @@ // Returns the connection icon ID for the given connection |status|. static int GetConnectionIconID(PageInfo::SiteConnectionStatus status); -#else +#else // !defined(OS_ANDROID) // Returns icons for the given PermissionInfo |info|. If |info|'s current // setting is CONTENT_SETTING_DEFAULT, it will return the icon for |info|'s // default setting.
diff --git a/chrome/browser/ui/search/local_ntp_browsertest.cc b/chrome/browser/ui/search/local_ntp_browsertest.cc index ade8263..95d183a7f 100644 --- a/chrome/browser/ui/search/local_ntp_browsertest.cc +++ b/chrome/browser/ui/search/local_ntp_browsertest.cc
@@ -26,6 +26,8 @@ #include "chrome/browser/search/search.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/browser/ui/location_bar/location_bar.h" #include "chrome/browser/ui/search/instant_test_utils.h" #include "chrome/browser/ui/search/local_ntp_browsertest_base.h" #include "chrome/browser/ui/search/local_ntp_test_utils.h" @@ -37,6 +39,7 @@ #include "chrome/test/base/ui_test_utils.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/ntp_tiles/constants.h" +#include "components/omnibox/browser/omnibox_view.h" #include "components/prefs/pref_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/interstitial_page.h" @@ -1190,6 +1193,53 @@ handle_observer.page_transition())); } +// This is a regression test for https://crbug.com/1020610 - it verifies that +// NTP navigations do show up as a pending navigation. +IN_PROC_BROWSER_TEST_F(LocalNTPTest, PendingNavigations) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // Open an NTP. + content::WebContents* ntp_tab = local_ntp_test_utils::OpenNewTab( + browser(), GURL(chrome::kChromeUINewTabURL)); + + // Inject and click a link to foo.com/hung and wait for the navigation to + // start. + GURL slow_url(embedded_test_server()->GetURL("/hung")); + const char* kNavScriptTemplate = R"( + var a = document.createElement('a'); + a.href = $1; + a.innerText = 'Simulated most-visited link'; + document.body.appendChild(a); + a.click(); + )"; + content::TestNavigationManager nav_manager(ntp_tab, slow_url); + ASSERT_TRUE(content::ExecuteScript( + ntp_tab, content::JsReplace(kNavScriptTemplate, slow_url))); + ASSERT_TRUE(nav_manager.WaitForRequestStart()); + + // Verify that the visible entry points at the |slow_url|. + content::NavigationEntry* pending_entry = + ntp_tab->GetController().GetPendingEntry(); + ASSERT_TRUE(pending_entry); + content::NavigationEntry* visible_entry = + ntp_tab->GetController().GetVisibleEntry(); + ASSERT_TRUE(visible_entry); + content::NavigationEntry* committed_entry = + ntp_tab->GetController().GetLastCommittedEntry(); + ASSERT_TRUE(committed_entry); + EXPECT_EQ(visible_entry, pending_entry); + EXPECT_EQ(slow_url, visible_entry->GetURL()); + EXPECT_NE(pending_entry, committed_entry); + EXPECT_NE(slow_url, committed_entry->GetURL()); + + // Verify that the omnibox displays |slow_url|. + OmniboxView* view = browser()->window()->GetLocationBar()->GetOmniboxView(); + std::string omnibox_text = base::UTF16ToUTF8(view->GetText()); + EXPECT_THAT(omnibox_text, ::testing::StartsWith(slow_url.host())); + EXPECT_THAT(omnibox_text, ::testing::EndsWith(slow_url.path())); + EXPECT_THAT(slow_url.spec(), ::testing::EndsWith(omnibox_text)); +} + // Verifies that Chrome won't spawn a separate renderer process for // every single NTP tab. This behavior goes all the way back to // the initial commit [1] which achieved that behavior by forcing
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc index ebc9310..6a99049 100644 --- a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc +++ b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.cc
@@ -59,32 +59,17 @@ // When enabled, closes the container upon any event in the window not // destined for the container and cancels the event. If an event is // destined for the container, it passes it through. -class WebUITabStripContainerView::AutoCloser : public ui::EventHandler, - public views::ViewObserver { +class WebUITabStripContainerView::AutoCloser : public ui::EventHandler { public: - AutoCloser(views::View* container, + using EventPassthroughPredicate = + base::RepeatingCallback<bool(const ui::Event& event)>; + + AutoCloser(EventPassthroughPredicate event_passthrough_predicate, base::RepeatingClosure close_container_callback) - : container_(container), - close_container_callback_(std::move(close_container_callback)), - view_observer_(this) { - view_observer_.Add(container); - WidgetChanged(); + : event_passthrough_predicate_(std::move(event_passthrough_predicate)), + close_container_callback_(std::move(close_container_callback)) {} - // Our observed Widget's NativeView may be destroyed before us. We - // have no reasonable way of un-registering our pre-target handler - // from the NativeView while the Widget is destroying. This disables - // EventHandler's check that it has been removed from all - // EventTargets. - DisableCheckTargets(); - } - - ~AutoCloser() override { - // If |container_| was in a Widget and that Widget still has its - // NativeView, remove ourselves from it. Otherwise, the NativeView - // is already destroying so we don't need to do anything. - if (last_widget_ && last_widget_->GetNativeView()) - last_widget_->GetNativeView()->RemovePreTargetHandler(this); - } + ~AutoCloser() override {} // Sets whether to inspect events. If not enabled, all events are // ignored and passed through as usual. @@ -94,54 +79,16 @@ void OnEvent(ui::Event* event) override { if (!enabled_) return; - if (!event->IsLocatedEvent()) + if (event_passthrough_predicate_.Run(*event)) return; - ui::LocatedEvent* located_event = event->AsLocatedEvent(); - // Let any events destined for |container_| pass through. - const gfx::Rect container_bounds_in_window = - container_->ConvertRectToWidget(container_->GetLocalBounds()); - if (container_bounds_in_window.Contains(located_event->root_location())) - return; - - // Upon any user action outside |container_|, cancel the event and close the - // container. - if (EventTypeCanCloseTabStrip(located_event->type())) { - located_event->StopPropagation(); - close_container_callback_.Run(); - } - } - - // views::ViewObserver: - void OnViewAddedToWidget(views::View* observed_view) override { - DCHECK_EQ(container_, observed_view); - WidgetChanged(); - } - - void OnViewRemovedFromWidget(views::View* observed_view) override { - DCHECK_EQ(container_, observed_view); - WidgetChanged(); + event->StopPropagation(); + close_container_callback_.Run(); } private: - // Handle when |container_| is added to a new Widget or removed from - // its Widget. - void WidgetChanged() { - views::Widget* new_widget = container_->GetWidget(); - if (new_widget == last_widget_) - return; - - if (last_widget_) - last_widget_->GetNativeView()->RemovePreTargetHandler(this); - if (new_widget) - new_widget->GetNativeView()->AddPreTargetHandler(this); - last_widget_ = new_widget; - } - - views::View* const container_; + EventPassthroughPredicate event_passthrough_predicate_; base::RepeatingClosure close_container_callback_; - views::Widget* last_widget_ = nullptr; - ScopedObserver<View, ViewObserver> view_observer_; bool enabled_ = false; }; @@ -182,7 +129,8 @@ AddChildView(std::make_unique<views::WebView>(browser->profile()))), tab_contents_container_(tab_contents_container), auto_closer_(std::make_unique<AutoCloser>( - this, + base::Bind(&WebUITabStripContainerView::EventShouldPropagate, + base::Unretained(this)), base::Bind(&WebUITabStripContainerView::CloseContainer, base::Unretained(this)))) { animation_.SetTweenType(gfx::Tween::Type::FAST_OUT_SLOW_IN); @@ -211,6 +159,13 @@ TabStripUI* const tab_strip_ui = static_cast<TabStripUI*>( web_view_->GetWebContents()->GetWebUI()->GetController()); tab_strip_ui->Initialize(browser_, this); + + // Our observed Widget's NativeView may be destroyed before us. We + // have no reasonable way of un-registering our pre-target handler + // from the NativeView while the Widget is destroying. This disables + // EventHandler's check that it has been removed from all + // EventTargets. + auto_closer_->DisableCheckTargets(); } WebUITabStripContainerView::~WebUITabStripContainerView() = default; @@ -221,14 +176,20 @@ std::unique_ptr<ToolbarButton> WebUITabStripContainerView::CreateNewTabButton() { + DCHECK_EQ(nullptr, new_tab_button_); auto new_tab_button = std::make_unique<ToolbarButton>(this); new_tab_button->SetID(VIEW_ID_WEBUI_TAB_STRIP_NEW_TAB_BUTTON); new_tab_button->SetTooltipText( l10n_util::GetStringUTF16(IDS_TOOLTIP_NEW_TAB)); + + new_tab_button_ = new_tab_button.get(); + view_observer_.Add(new_tab_button_); + return new_tab_button; } std::unique_ptr<views::View> WebUITabStripContainerView::CreateTabCounter() { + DCHECK_EQ(nullptr, tab_counter_); // TODO(999557): Create a custom text style to get the correct size/weight. // TODO(999557): Figure out how to get the right font. auto tab_counter = std::make_unique<views::LabelButton>( @@ -259,6 +220,9 @@ browser_->tab_strip_model()->AddObserver(tab_counter_model_observer_.get()); tab_counter_model_observer_->UpdateCounter(browser_->tab_strip_model()); + tab_counter_ = tab_counter.get(); + view_observer_.Add(tab_counter_); + return tab_counter; } @@ -279,6 +243,30 @@ auto_closer_->set_enabled(target_visible); } +bool WebUITabStripContainerView::EventShouldPropagate(const ui::Event& event) { + if (!event.IsLocatedEvent()) + return true; + const ui::LocatedEvent* located_event = event.AsLocatedEvent(); + + if (!EventTypeCanCloseTabStrip(located_event->type())) + return true; + + // If the event is in the container or control buttons, let it be handled. + for (views::View* view : + {static_cast<views::View*>(this), new_tab_button_, tab_counter_}) { + if (!view) + continue; + + const gfx::Rect bounds_in_window = + view->ConvertRectToWidget(view->GetLocalBounds()); + if (bounds_in_window.Contains(located_event->root_location())) + return true; + } + + // Otherwise, cancel the event and close the container. + return false; +} + void WebUITabStripContainerView::AnimationEnded( const gfx::Animation* animation) { DCHECK_EQ(&animation_, animation); @@ -309,6 +297,16 @@ tab_contents_container_->size()); } +void WebUITabStripContainerView::AddedToWidget() { + GetWidget()->GetNativeView()->AddPreTargetHandler(auto_closer_.get()); +} + +void WebUITabStripContainerView::RemovedFromWidget() { + aura::Window* const native_view = GetWidget()->GetNativeView(); + if (native_view) + native_view->RemovePreTargetHandler(auto_closer_.get()); +} + int WebUITabStripContainerView::GetHeightForWidth(int w) const { return desired_height_ * animation_.GetCurrentValue(); } @@ -325,7 +323,9 @@ } void WebUITabStripContainerView::OnViewBoundsChanged(View* observed_view) { - DCHECK_EQ(tab_contents_container_, observed_view); + if (observed_view != tab_contents_container_) + return; + desired_height_ = TabStripUILayout::CalculateForWebViewportSize(observed_view->size()) .CalculateContainerHeight(); @@ -338,3 +338,10 @@ web_view_->GetWebContents()->GetWebUI()->GetController()); tab_strip_ui->LayoutChanged(); } + +void WebUITabStripContainerView::OnViewIsDeleting(View* observed_view) { + if (observed_view == new_tab_button_) + new_tab_button_ = nullptr; + else if (observed_view == tab_counter_) + tab_counter_ = nullptr; +}
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h index 5841c4b..28d262b 100644 --- a/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h +++ b/chrome/browser/ui/views/frame/webui_tab_strip_container_view.h
@@ -44,7 +44,7 @@ views::NativeViewHost* GetNativeViewHost(); - // Control buttons. + // Control buttons. Each must only be called once. std::unique_ptr<ToolbarButton> CreateNewTabButton(); std::unique_ptr<views::View> CreateTabCounter(); @@ -53,6 +53,11 @@ void SetContainerTargetVisibility(bool target_visible); + // When the container is open, it intercepts most tap and click + // events. This checks if each event should be intercepted or passed + // through to its target. + bool EventShouldPropagate(const ui::Event& event); + // TabStripUI::Embedder: void CloseContainer() override; void ShowContextMenuAtPoint( @@ -61,6 +66,8 @@ TabStripUILayout GetLayout() override; // views::View: + void AddedToWidget() override; + void RemovedFromWidget() override; int GetHeightForWidth(int w) const override; // gfx::AnimationDelegate: @@ -72,10 +79,13 @@ // views::ViewObserver: void OnViewBoundsChanged(View* observed_view) override; + void OnViewIsDeleting(View* observed_view) override; Browser* const browser_; views::WebView* const web_view_; views::View* const tab_contents_container_; + views::View* new_tab_button_ = nullptr; + views::View* tab_counter_ = nullptr; int desired_height_ = 0;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc index 02e0de155..16e9fea 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.cc
@@ -194,11 +194,6 @@ model_->SetSelectedLineState(OmniboxPopupModel::NORMAL); } -void OmniboxPopupContentsView::ProvideButtonFocusHint(size_t line) { - OmniboxResultView* result = result_view_at(line); - result->ProvideButtonFocusHint(); -} - bool OmniboxPopupContentsView::InExplicitExperimentalKeywordMode() { return model_->edit_model()->InExplicitExperimentalKeywordMode(); } @@ -300,6 +295,10 @@ InvalidateLayout(); } +void OmniboxPopupContentsView::ProvideButtonFocusHint(size_t line) { + result_view_at(line)->ProvideButtonFocusHint(); +} + void OmniboxPopupContentsView::OnMatchIconUpdated(size_t match_index) { result_view_at(match_index)->OnMatchIconUpdated(); }
diff --git a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h index cfb7155..7f80af3 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h +++ b/chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h
@@ -60,9 +60,6 @@ // Called by the active result view to inform model (due to mouse event). void UnselectButton(); - // Called to inform result view of button focus. - void ProvideButtonFocusHint(size_t line); - // Returns whether we're in experimental keyword mode and the input gives // sufficient confidence that the user wants keyword mode. bool InExplicitExperimentalKeywordMode(); @@ -72,6 +69,7 @@ void InvalidateLine(size_t line) override; void OnLineSelected(size_t line) override; void UpdatePopupAppearance() override; + void ProvideButtonFocusHint(size_t line) override; void OnMatchIconUpdated(size_t match_index) override; void OnDragCanceled() override;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc index 309d734c..131cd34 100644 --- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc +++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -671,8 +671,6 @@ model()->popup_model()->SelectedLineHasTabMatch()) { model()->popup_model()->SetSelectedLineState( OmniboxPopupModel::BUTTON_FOCUSED); - popup_view_->ProvideButtonFocusHint( - model()->popup_model()->selected_line()); } return true; @@ -715,8 +713,6 @@ OmniboxPopupModel::NORMAL) { model()->popup_model()->SetSelectedLineState( OmniboxPopupModel::BUTTON_FOCUSED); - popup_view_->ProvideButtonFocusHint( - model()->popup_model()->selected_line()); return true; } return false;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc index 115c695..b0c55e9 100644 --- a/chrome/browser/ui/views/toolbar/toolbar_view.cc +++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -756,7 +756,7 @@ views::View* ToolbarView::GetDefaultExtensionDialogAnchorView() { if (extensions_container_) - return extensions_container_; + return extensions_container_->extensions_button(); return GetAppMenuButton(); }
diff --git a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc index c5fc69c..c0e86a1 100644 --- a/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc +++ b/chrome/browser/ui/web_applications/web_app_file_handling_browsertest.cc
@@ -11,6 +11,7 @@ #include "chrome/browser/apps/launch_service/launch_service.h" #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" #include "chrome/common/web_application_info.h" +#include "content/public/test/browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" #include "third_party/blink/public/common/features.h" @@ -81,6 +82,13 @@ apps::LaunchService::Get(profile())->OpenApplication(params); navigation_observer.Wait(); + + // Attach the launchParams to the window so we can inspect them easily. + auto result = content::EvalJs(web_contents, + "launchQueue.setConsumer(launchParams => {" + " window.launchParams = launchParams;" + "});"); + return web_contents; } @@ -93,7 +101,7 @@ const std::string app_id = InstallFileHandlingPWA(); content::WebContents* web_contents = LaunchWithFiles(app_id, {}); - EXPECT_EQ(0, content::EvalJs(web_contents, "launchParams.files.length")); + EXPECT_EQ(false, content::EvalJs(web_contents, "!!window.launchParams")); } IN_PROC_BROWSER_TEST_P(WebAppFileHandlingBrowserTest, @@ -105,9 +113,10 @@ content::WebContents* web_contents = LaunchWithFiles(app_id, {test_file_path}); - EXPECT_EQ(1, content::EvalJs(web_contents, "launchParams.files.length")); + EXPECT_EQ(1, + content::EvalJs(web_contents, "window.launchParams.files.length")); EXPECT_EQ(test_file_path.BaseName().value(), - content::EvalJs(web_contents, "launchParams.files[0].name")); + content::EvalJs(web_contents, "window.launchParams.files[0].name")); } INSTANTIATE_TEST_SUITE_P(
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm b/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm index 24d289f5..79941fa 100644 --- a/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm +++ b/chrome/browser/web_applications/components/web_app_shortcut_mac_unittest.mm
@@ -20,6 +20,8 @@ #include "base/path_service.h" #include "base/strings/sys_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/common/chrome_features.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" #import "chrome/common/mac/app_mode_common.h" @@ -348,6 +350,11 @@ } TEST_F(WebAppShortcutCreatorTest, DeleteAllShortcutsForProfile) { + base::test::ScopedFeatureList scoped_features; + scoped_features.InitWithFeatures( + /*enabled_features=*/{}, + /*disabled_features=*/{features::kAppShimMultiProfile}); + NiceMock<WebAppShortcutCreatorMock> shortcut_creator(app_data_dir_, info_.get()); base::FilePath profile_path = info_->profile_path;
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc index 6fa7942a..76a556a6 100644 --- a/chrome/common/chrome_features.cc +++ b/chrome/common/chrome_features.cc
@@ -37,7 +37,7 @@ // Enable the new multi-profile-aware app shim mode. // TODO(https://crbug.com/982024): Delete this flag when feature is complete. const base::Feature kAppShimMultiProfile{"AppShimMultiProfile", - base::FEATURE_DISABLED_BY_DEFAULT}; + base::FEATURE_ENABLED_BY_DEFAULT}; // Can be used to disable RemoteCocoa (hosting NSWindows for apps in the app // process). For debugging purposes only.
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index 3db2f17..3a8e702 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -500,6 +500,7 @@ const char* const kChromeHostURLs[] = { kChromeUIAboutHost, kChromeUIAccessibilityHost, + kChromeUIAutofillInternalsHost, kChromeUIBluetoothInternalsHost, kChromeUIChromeURLsHost, kChromeUIComponentsHost,
diff --git a/chrome/installer/mac/sign_chrome.py b/chrome/installer/mac/sign_chrome.py index 54ecbb05..4f24534 100755 --- a/chrome/installer/mac/sign_chrome.py +++ b/chrome/installer/mac/sign_chrome.py
@@ -81,9 +81,6 @@ parser = argparse.ArgumentParser( description='Code sign and package Chrome for channel distribution.') parser.add_argument( - '--keychain', - help='The keychain to load the identity from. OBSOLETE AND INGORED.') - parser.add_argument( '--identity', required=True, help='The identity to sign everything but PKGs with.')
diff --git a/chrome/renderer/content_settings_agent_impl.cc b/chrome/renderer/content_settings_agent_impl.cc index a0accbab..e3fd5300 100644 --- a/chrome/renderer/content_settings_agent_impl.cc +++ b/chrome/renderer/content_settings_agent_impl.cc
@@ -125,9 +125,7 @@ render_frame->GetAssociatedInterfaceRegistry()->AddInterface( base::Bind(&ContentSettingsAgentImpl::OnContentSettingsAgentRequest, base::Unretained(this))); - - render_frame->GetBrowserInterfaceBroker()->GetInterface( - content_settings_manager_.BindNewPipeAndPassReceiver()); + EnsureContentSettingsManagerConnection(); content::RenderFrame* main_frame = render_frame->GetRenderView()->GetMainRenderFrame(); @@ -147,6 +145,16 @@ ContentSettingsAgentImpl::~ContentSettingsAgentImpl() {} +void ContentSettingsAgentImpl::EnsureContentSettingsManagerConnection() { + if (content_settings_manager_.is_bound() && + content_settings_manager_.is_connected()) + return; + + content_settings_manager_.reset(); + render_frame()->GetBrowserInterfaceBroker()->GetInterface( + content_settings_manager_.BindNewPipeAndPassReceiver()); +} + #if BUILDFLAG(ENABLE_EXTENSIONS) void ContentSettingsAgentImpl::SetExtensionDispatcher( extensions::Dispatcher* extension_dispatcher) { @@ -204,6 +212,8 @@ if (frame->Parent()) return; // Not a top-level navigation. + EnsureContentSettingsManagerConnection(); + if (!is_same_document_navigation) { // Clear "block" flags for the new page. This needs to happen before any of // |allowScript()|, |allowScriptFromSource()|, |allowImage()|, or
diff --git a/chrome/renderer/content_settings_agent_impl.h b/chrome/renderer/content_settings_agent_impl.h index 91dfe7c..b9530532ae 100644 --- a/chrome/renderer/content_settings_agent_impl.h +++ b/chrome/renderer/content_settings_agent_impl.h
@@ -165,6 +165,9 @@ bool AllowStorageAccess( chrome::mojom::ContentSettingsManager::StorageType storage_type); + // Ensures that |content_settings_manager_| is connected. + void EnsureContentSettingsManagerConnection(); + mojo::Remote<chrome::mojom::ContentSettingsManager> content_settings_manager_; #if BUILDFLAG(ENABLE_EXTENSIONS)
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.cc b/chrome/renderer/extensions/cast_streaming_native_handler.cc index dd9509e4..46b4abd 100644 --- a/chrome/renderer/extensions/cast_streaming_native_handler.cc +++ b/chrome/renderer/extensions/cast_streaming_native_handler.cc
@@ -64,8 +64,6 @@ constexpr char kInvalidAesKey[] = "Invalid value for AES key"; constexpr char kInvalidDestination[] = "Invalid destination"; constexpr char kInvalidRtpParams[] = "Invalid value for RTP params"; -constexpr char kInvalidLatency[] = "Invalid value for max_latency. (0-1000)"; -constexpr char kInvalidRtpTimebase[] = "Invalid rtp_timebase. (1000-1000000)"; constexpr char kInvalidStreamArgs[] = "Invalid stream arguments"; constexpr char kRtpStreamNotFound[] = "The RTP stream cannot be found"; constexpr char kUdpTransportNotFound[] = "The UDP transport cannot be found"; @@ -800,90 +798,6 @@ return NULL; } -bool CastStreamingNativeHandler::FrameReceiverConfigFromArg( - v8::Isolate* isolate, - const v8::Local<v8::Value>& arg, - media::cast::FrameReceiverConfig* config) const { - std::unique_ptr<base::Value> params_value = - V8ValueConverter::Create()->FromV8Value(arg, context()->v8_context()); - if (!params_value) { - isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kUnableToConvertParams, - v8::NewStringType::kNormal) - .ToLocalChecked())); - return false; - } - std::unique_ptr<RtpReceiverParams> params = - RtpReceiverParams::FromValue(*params_value); - if (!params) { - isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidRtpParams, - v8::NewStringType::kNormal) - .ToLocalChecked())); - return false; - } - - config->receiver_ssrc = params->receiver_ssrc; - config->sender_ssrc = params->sender_ssrc; - config->rtp_max_delay_ms = params->max_latency; - if (config->rtp_max_delay_ms < 0 || config->rtp_max_delay_ms > 1000) { - isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidLatency, - v8::NewStringType::kNormal) - .ToLocalChecked())); - return false; - } - config->channels = 2; - if (params->codec_name == "OPUS") { - config->codec = media::cast::CODEC_AUDIO_OPUS; - config->rtp_timebase = 48000; - config->rtp_payload_type = media::cast::RtpPayloadType::AUDIO_OPUS; - } else if (params->codec_name == "PCM16") { - config->codec = media::cast::CODEC_AUDIO_PCM16; - config->rtp_timebase = 48000; - config->rtp_payload_type = media::cast::RtpPayloadType::AUDIO_PCM16; - } else if (params->codec_name == "AAC") { - config->codec = media::cast::CODEC_AUDIO_AAC; - config->rtp_timebase = 48000; - config->rtp_payload_type = media::cast::RtpPayloadType::AUDIO_AAC; - } else if (params->codec_name == "VP8") { - config->codec = media::cast::CODEC_VIDEO_VP8; - config->rtp_timebase = 90000; - config->rtp_payload_type = media::cast::RtpPayloadType::VIDEO_VP8; - } else if (params->codec_name == "H264") { - config->codec = media::cast::CODEC_VIDEO_H264; - config->rtp_timebase = 90000; - config->rtp_payload_type = media::cast::RtpPayloadType::VIDEO_H264; - } - if (params->rtp_timebase) { - config->rtp_timebase = *params->rtp_timebase; - if (config->rtp_timebase < 1000 || config->rtp_timebase > 1000000) { - isolate->ThrowException(v8::Exception::TypeError( - v8::String::NewFromUtf8(isolate, kInvalidRtpTimebase, - v8::NewStringType::kNormal) - .ToLocalChecked())); - return false; - } - } - if (params->aes_key && - !HexDecode(*params->aes_key, &config->aes_key)) { - isolate->ThrowException( - v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesKey, - v8::NewStringType::kNormal) - .ToLocalChecked())); - return false; - } - if (params->aes_iv_mask && - !HexDecode(*params->aes_iv_mask, &config->aes_iv_mask)) { - isolate->ThrowException( - v8::Exception::Error(v8::String::NewFromUtf8(isolate, kInvalidAesIvMask, - v8::NewStringType::kNormal) - .ToLocalChecked())); - return false; - } - return true; -} - bool CastStreamingNativeHandler::IPEndPointFromArg( v8::Isolate* isolate, const v8::Local<v8::Value>& arg,
diff --git a/chrome/renderer/extensions/cast_streaming_native_handler.h b/chrome/renderer/extensions/cast_streaming_native_handler.h index 6fdcc7b2..9f135b3 100644 --- a/chrome/renderer/extensions/cast_streaming_native_handler.h +++ b/chrome/renderer/extensions/cast_streaming_native_handler.h
@@ -25,12 +25,6 @@ class IPEndPoint; } -namespace media { -namespace cast { -struct FrameReceiverConfig; -} -} - namespace extensions { class NativeExtensionBindingsSystem; @@ -103,15 +97,6 @@ CastRtpStream* GetRtpStreamOrThrow(int stream_id) const; CastUdpTransport* GetUdpTransportOrThrow(int transport_id) const; - // Fills out a media::cast::FrameReceiverConfig from the v8 - // equivialent. (cast.streaming.receiverSession.RtpReceiverParams) - // Returns true if everything was ok, raises a v8 exception and - // returns false if anything went wrong. - bool FrameReceiverConfigFromArg( - v8::Isolate* isolate, - const v8::Local<v8::Value>& arg, - media::cast::FrameReceiverConfig* config) const; - bool IPEndPointFromArg(v8::Isolate* isolate, const v8::Local<v8::Value>& arg, net::IPEndPoint* ip_endpoint) const;
diff --git a/chromecast/bindings/bindings_manager_cast_browsertest.cc b/chromecast/bindings/bindings_manager_cast_browsertest.cc index fe99d318..43ddcc5 100644 --- a/chromecast/bindings/bindings_manager_cast_browsertest.cc +++ b/chromecast/bindings/bindings_manager_cast_browsertest.cc
@@ -12,6 +12,7 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/strings/string_piece.h" @@ -266,7 +267,9 @@ DISALLOW_COPY_AND_ASSIGN(MockWebContentsDelegate); }; -class MockCastWebContentsDelegate : public CastWebContents::Delegate { +class MockCastWebContentsDelegate + : public base::SupportsWeakPtr<MockCastWebContentsDelegate>, + public CastWebContents::Delegate { public: MockCastWebContentsDelegate() {} ~MockCastWebContentsDelegate() override = default; @@ -311,9 +314,10 @@ // CastWebContents::Delegate must be set for receiving PageStateChanged // event. - CastWebContents::InitParams init_params = { - &mock_cast_wc_delegate_ /* delegate */, false /* enabled_for_dev */, - false /* use_cma_renderer */, true /* is_root_window */}; + CastWebContents::InitParams init_params; + init_params.delegate = mock_cast_wc_delegate_.AsWeakPtr(); + init_params.is_root_window = true; + cast_web_contents_ = std::make_unique<CastWebContentsImpl>(web_contents_.get(), init_params); title_change_observer_.Observe(cast_web_contents_.get());
diff --git a/chromecast/browser/BUILD.gn b/chromecast/browser/BUILD.gn index 2320297..3371115 100644 --- a/chromecast/browser/BUILD.gn +++ b/chromecast/browser/BUILD.gn
@@ -89,8 +89,8 @@ "cast_system_memory_pressure_evaluator_adjuster.h", "cast_web_contents_impl.cc", "cast_web_contents_impl.h", - "cast_web_contents_manager.cc", - "cast_web_contents_manager.h", + "cast_web_service.cc", + "cast_web_service.h", "cast_web_view_default.cc", "cast_web_view_default.h", "cast_web_view_factory.cc", @@ -212,7 +212,7 @@ "android/cast_content_window_android.cc", "android/cast_content_window_android.h", "android/cast_metrics_helper_android.cc", - "android/cast_web_contents_manager_android.cc", + "android/cast_web_service_android.cc", ] deps += [ ":jni_headers", @@ -248,7 +248,7 @@ sources += [ "cast_content_window_aura.cc", "cast_content_window_aura.h", - "cast_web_contents_manager_aura.cc", + "cast_web_service_aura.cc", ] deps += [
diff --git a/chromecast/browser/android/cast_content_window_android.cc b/chromecast/browser/android/cast_content_window_android.cc index 018932f..7a1193d5 100644 --- a/chromecast/browser/android/cast_content_window_android.cc +++ b/chromecast/browser/android/cast_content_window_android.cc
@@ -39,15 +39,14 @@ CastContentWindowAndroid::CastContentWindowAndroid( const CastContentWindow::CreateParams& params) - : delegate_(params.delegate), + : CastContentWindow(params), + activity_id_(delegate_->GetId()), java_window_(CreateJavaWindow(reinterpret_cast<jlong>(this), params.is_headless, params.enable_touch_input, params.is_remote_control_mode, params.turn_on_screen, - params.session_id)) { - DCHECK(delegate_); -} + params.session_id)) {} CastContentWindowAndroid::~CastContentWindowAndroid() { JNIEnv* env = base::android::AttachCurrentThread(); @@ -85,7 +84,9 @@ void CastContentWindowAndroid::OnActivityStopped( JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller) { - delegate_->OnWindowDestroyed(); + if (delegate_) { + delegate_->OnWindowDestroyed(); + } } void CastContentWindowAndroid::RequestVisibility( @@ -102,7 +103,9 @@ void CastContentWindowAndroid::NotifyVisibilityChange( VisibilityType visibility_type) { - delegate_->OnVisibilityChange(visibility_type); + if (delegate_) { + delegate_->OnVisibilityChange(visibility_type); + } for (auto& observer : observer_list_) { observer.OnVisibilityChange(visibility_type); } @@ -117,7 +120,10 @@ JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller, int gesture_type) { - return delegate_->ConsumeGesture(static_cast<GestureType>(gesture_type)); + if (delegate_) { + return delegate_->ConsumeGesture(static_cast<GestureType>(gesture_type)); + } + return false; } void CastContentWindowAndroid::OnVisibilityChange( @@ -130,7 +136,7 @@ base::android::ScopedJavaLocalRef<jstring> CastContentWindowAndroid::GetId( JNIEnv* env, const base::android::JavaParamRef<jobject>& jcaller) { - return ConvertUTF8ToJavaString(env, delegate_->GetId()); + return ConvertUTF8ToJavaString(env, activity_id_); } } // namespace chromecast
diff --git a/chromecast/browser/android/cast_content_window_android.h b/chromecast/browser/android/cast_content_window_android.h index 67ce1f8..57e9558 100644 --- a/chromecast/browser/android/cast_content_window_android.h +++ b/chromecast/browser/android/cast_content_window_android.h
@@ -53,7 +53,7 @@ const base::android::JavaParamRef<jobject>& jcaller); private: - CastContentWindow::Delegate* const delegate_; + const std::string activity_id_; base::android::ScopedJavaGlobalRef<jobject> java_window_; DISALLOW_COPY_AND_ASSIGN(CastContentWindowAndroid);
diff --git a/chromecast/browser/android/cast_web_contents_manager_android.cc b/chromecast/browser/android/cast_web_service_android.cc similarity index 76% rename from chromecast/browser/android/cast_web_contents_manager_android.cc rename to chromecast/browser/android/cast_web_service_android.cc index e06487c..b6ccdaa 100644 --- a/chromecast/browser/android/cast_web_contents_manager_android.cc +++ b/chromecast/browser/android/cast_web_service_android.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromecast/browser/cast_web_contents_manager.h" +#include "chromecast/browser/cast_web_service.h" #include <memory> @@ -10,7 +10,7 @@ namespace chromecast { -std::unique_ptr<CastContentWindow> CastWebContentsManager::CreateWindow( +std::unique_ptr<CastContentWindow> CastWebService::CreateWindow( const CastContentWindow::CreateParams& params) { return std::make_unique<CastContentWindowAndroid>(params); }
diff --git a/chromecast/browser/cast_content_gesture_handler.cc b/chromecast/browser/cast_content_gesture_handler.cc index 141f649..a6390bf 100644 --- a/chromecast/browser/cast_content_gesture_handler.cc +++ b/chromecast/browser/cast_content_gesture_handler.cc
@@ -13,7 +13,7 @@ } // namespace CastContentGestureHandler::CastContentGestureHandler( - CastContentWindow::Delegate* delegate, + base::WeakPtr<CastContentWindow::Delegate> delegate, bool enable_top_drag_gesture) : priority_(Priority::NONE), enable_top_drag_gesture_(enable_top_drag_gesture), @@ -25,11 +25,13 @@ } CastContentGestureHandler::CastContentGestureHandler( - CastContentWindow::Delegate* delegate) + base::WeakPtr<CastContentWindow::Delegate> delegate) : CastContentGestureHandler( delegate, GetSwitchValueBoolean(switches::kEnableTopDragGesture, false)) {} +CastContentGestureHandler::~CastContentGestureHandler() = default; + void CastContentGestureHandler::SetPriority( CastGestureHandler::Priority priority) { priority_ = priority; @@ -41,6 +43,8 @@ bool CastContentGestureHandler::CanHandleSwipe( CastSideSwipeOrigin swipe_origin) { + if (!delegate_) + return false; return delegate_->CanHandleGesture(GestureForSwipeOrigin(swipe_origin)); } @@ -66,7 +70,6 @@ if (!CanHandleSwipe(swipe_origin)) { return; } - GestureType gesture_type = GestureForSwipeOrigin(swipe_origin); switch (event) { @@ -102,7 +105,7 @@ void CastContentGestureHandler::HandleTapDownGesture( const gfx::Point& touch_location) { - if (!delegate_->CanHandleGesture(GestureType::TAP_DOWN)) { + if (!delegate_ || !delegate_->CanHandleGesture(GestureType::TAP_DOWN)) { return; } delegate_->ConsumeGesture(GestureType::TAP_DOWN); @@ -110,7 +113,7 @@ void CastContentGestureHandler::HandleTapGesture( const gfx::Point& touch_location) { - if (!delegate_->CanHandleGesture(GestureType::TAP)) { + if (!delegate_ || !delegate_->CanHandleGesture(GestureType::TAP)) { return; } delegate_->ConsumeGesture(GestureType::TAP);
diff --git a/chromecast/browser/cast_content_gesture_handler.h b/chromecast/browser/cast_content_gesture_handler.h index 1291ac04..2071c67d 100644 --- a/chromecast/browser/cast_content_gesture_handler.h +++ b/chromecast/browser/cast_content_gesture_handler.h
@@ -6,6 +6,7 @@ #define CHROMECAST_BROWSER_CAST_CONTENT_GESTURE_HANDLER_H_ #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "base/timer/elapsed_timer.h" #include "chromecast/browser/cast_content_window.h" #include "chromecast/graphics/gestures/cast_gesture_handler.h" @@ -16,7 +17,9 @@ // CastContentWindow::Delegate. class CastContentGestureHandler : public CastGestureHandler { public: - explicit CastContentGestureHandler(CastContentWindow::Delegate* delegate); + explicit CastContentGestureHandler( + base::WeakPtr<CastContentWindow::Delegate> delegate); + ~CastContentGestureHandler() override; // CastGestureHandler implementation: Priority GetPriority() override; @@ -31,7 +34,7 @@ private: friend class CastContentGestureHandlerTest; - CastContentGestureHandler(CastContentWindow::Delegate* delegate, + CastContentGestureHandler(base::WeakPtr<CastContentWindow::Delegate> delegate, bool enable_top_drag_gesture); GestureType GestureForSwipeOrigin(CastSideSwipeOrigin swipe_origin); @@ -41,7 +44,7 @@ // Number of pixels past swipe origin to consider as a back gesture. const int back_horizontal_threshold_; - CastContentWindow::Delegate* const delegate_; + base::WeakPtr<CastContentWindow::Delegate> const delegate_; base::ElapsedTimer current_swipe_time_; };
diff --git a/chromecast/browser/cast_content_gesture_handler_test.cc b/chromecast/browser/cast_content_gesture_handler_test.cc index 03e1917f2..271deaf 100644 --- a/chromecast/browser/cast_content_gesture_handler_test.cc +++ b/chromecast/browser/cast_content_gesture_handler_test.cc
@@ -4,6 +4,7 @@ #include "chromecast/browser/cast_content_gesture_handler.h" +#include "base/memory/weak_ptr.h" #include "chromecast/base/chromecast_switches.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_base.h" @@ -39,7 +40,9 @@ } // namespace -class MockCastContentWindowDelegate : public CastContentWindow::Delegate { +class MockCastContentWindowDelegate + : public base::SupportsWeakPtr<MockCastContentWindowDelegate>, + public CastContentWindow::Delegate { public: ~MockCastContentWindowDelegate() override = default; @@ -56,7 +59,7 @@ class CastContentGestureHandlerTest : public testing::Test { public: - CastContentGestureHandlerTest() : dispatcher_(&delegate_, true) {} + CastContentGestureHandlerTest() : dispatcher_(delegate_.AsWeakPtr(), true) {} protected: MockCastContentWindowDelegate delegate_;
diff --git a/chromecast/browser/cast_content_window.cc b/chromecast/browser/cast_content_window.cc index 90adeab..ebe3ea59 100644 --- a/chromecast/browser/cast_content_window.cc +++ b/chromecast/browser/cast_content_window.cc
@@ -6,13 +6,15 @@ namespace chromecast { -CastContentWindow::CastContentWindow() = default; +CastContentWindow::CastContentWindow(const CreateParams& params) + : delegate_(params.delegate) {} CastContentWindow::~CastContentWindow() = default; CastContentWindow::CreateParams::CreateParams() = default; CastContentWindow::CreateParams::CreateParams(const CreateParams& other) = default; +CastContentWindow::CreateParams::~CreateParams() = default; void CastContentWindow::AddObserver(Observer* observer) { observer_list_.AddObserver(observer);
diff --git a/chromecast/browser/cast_content_window.h b/chromecast/browser/cast_content_window.h index 3973f6e..c62b1b5b 100644 --- a/chromecast/browser/cast_content_window.h +++ b/chromecast/browser/cast_content_window.h
@@ -128,8 +128,10 @@ // The parameters used to create a CastContentWindow instance. struct CreateParams { - // The delegate for the CastContentWindow. Must be non-null. - Delegate* delegate = nullptr; + // The delegate for the CastContentWindow. Must be non-null. If the delegate + // is destroyed before CastContentWindow, the WeakPtr will be invalidated on + // the main UI thread. + base::WeakPtr<Delegate> delegate = nullptr; // True if this CastContentWindow is for a headless build. bool is_headless = false; @@ -152,6 +154,7 @@ CreateParams(); CreateParams(const CreateParams& other); + ~CreateParams(); }; class Observer : public base::CheckedObserver { @@ -163,7 +166,7 @@ ~Observer() override {} }; - CastContentWindow(); + explicit CastContentWindow(const CreateParams& params); virtual ~CastContentWindow(); // Creates a full-screen window for |cast_web_contents| and displays it if @@ -218,6 +221,7 @@ void RemoveObserver(Observer* observer); protected: + base::WeakPtr<Delegate> delegate_; base::ObserverList<Observer> observer_list_; };
diff --git a/chromecast/browser/cast_content_window_aura.cc b/chromecast/browser/cast_content_window_aura.cc index e9b1b76d..068cae6 100644 --- a/chromecast/browser/cast_content_window_aura.cc +++ b/chromecast/browser/cast_content_window_aura.cc
@@ -72,16 +72,14 @@ CastContentWindowAura::CastContentWindowAura( const CastContentWindow::CreateParams& params, CastWindowManager* window_manager) - : delegate_(params.delegate), + : CastContentWindow(params), window_manager_(window_manager), gesture_dispatcher_( std::make_unique<CastContentGestureHandler>(delegate_)), gesture_priority_(params.gesture_priority), is_touch_enabled_(params.enable_touch_input), window_(nullptr), - has_screen_access_(false) { - DCHECK(delegate_); -} + has_screen_access_(false) {} CastContentWindowAura::~CastContentWindowAura() { CastWebContents::Observer::Observe(nullptr); @@ -167,7 +165,9 @@ void CastContentWindowAura::NotifyVisibilityChange( VisibilityType visibility_type) { - delegate_->OnVisibilityChange(visibility_type); + if (delegate_) { + delegate_->OnVisibilityChange(visibility_type); + } for (auto& observer : observer_list_) { observer.OnVisibilityChange(visibility_type); }
diff --git a/chromecast/browser/cast_content_window_aura.h b/chromecast/browser/cast_content_window_aura.h index 73e826b..bff975c2 100644 --- a/chromecast/browser/cast_content_window_aura.h +++ b/chromecast/browser/cast_content_window_aura.h
@@ -50,7 +50,6 @@ void OnWindowDestroyed(aura::Window* window) override; private: - CastContentWindow::Delegate* const delegate_; CastWindowManager* const window_manager_; // Utility class for detecting and dispatching gestures to delegates.
diff --git a/chromecast/browser/cast_web_contents.cc b/chromecast/browser/cast_web_contents.cc index ff2d4cc7..855d153 100644 --- a/chromecast/browser/cast_web_contents.cc +++ b/chromecast/browser/cast_web_contents.cc
@@ -33,4 +33,8 @@ cast_web_contents_ = nullptr; } +CastWebContents::InitParams::InitParams() = default; +CastWebContents::InitParams::InitParams(const InitParams& other) = default; +CastWebContents::InitParams::~InitParams() = default; + } // namespace chromecast
diff --git a/chromecast/browser/cast_web_contents.h b/chromecast/browser/cast_web_contents.h index cb61f16..6f08898 100644 --- a/chromecast/browser/cast_web_contents.h +++ b/chromecast/browser/cast_web_contents.h
@@ -56,7 +56,7 @@ // We consider the CastWebContents to be in a LOADED state when the content of // the main frame is fully loaded and running (all resources fetched, JS is // running). Iframes might still be loading in this case, but in general we -// consider the page to be in a presentable state at this stage. It is +// consider the page to be in a presentable state at this stage, so it is // appropriate to display the WebContents to the user. // // During or after the page is loaded, there are multiple error conditions that @@ -184,8 +184,10 @@ // Initialization parameters for CastWebContents. struct InitParams { - // Delegate for CastWebContents. This can be null for an inner WebContents. - Delegate* delegate = nullptr; + // The delegate for the CastWebContents. Must be non-null. If the delegate + // is destroyed before CastWebContents, the WeakPtr will be invalidated on + // the main UI thread. + base::WeakPtr<Delegate> delegate = nullptr; // Enable development mode for this CastWebCastWebContents. Whitelists // certain functionality for the WebContents, like remote debugging and // debugging interfaces. @@ -204,6 +206,10 @@ // Background color for the WebContents view. If not provided, the color // will fall back to the platform default. BackgroundColor background_color = BackgroundColor::NONE; + + InitParams(); + InitParams(const InitParams& other); + ~InitParams(); }; // Page state for the main frame. @@ -234,9 +240,6 @@ // Initialization and Setup // =========================================================================== - // Set the delegate. SetDelegate(nullptr) can be used to stop notifications. - virtual void SetDelegate(Delegate* delegate) = 0; - // Add a set of features for all renderers in the WebContents. Features are // configured when `CastWebContents::RenderFrameCreated` is invoked. virtual void AddRendererFeatures(std::vector<RendererFeature> features) = 0;
diff --git a/chromecast/browser/cast_web_contents_browsertest.cc b/chromecast/browser/cast_web_contents_browsertest.cc index 3a3960bd..bd3fdeb7 100644 --- a/chromecast/browser/cast_web_contents_browsertest.cc +++ b/chromecast/browser/cast_web_contents_browsertest.cc
@@ -101,7 +101,9 @@ // ============================================================================= // Mocks // ============================================================================= -class MockCastWebContentsDelegate : public CastWebContents::Delegate { +class MockCastWebContentsDelegate + : public base::SupportsWeakPtr<MockCastWebContentsDelegate>, + public CastWebContents::Delegate { public: MockCastWebContentsDelegate() {} ~MockCastWebContentsDelegate() override = default; @@ -273,9 +275,10 @@ web_contents_ = content::WebContents::Create(create_params); web_contents_->SetDelegate(&mock_wc_delegate_); - CastWebContents::InitParams init_params = { - &mock_cast_wc_delegate_, false /* enabled_for_dev */, - false /* use_cma_renderer */, true /* is_root_window */}; + CastWebContents::InitParams init_params; + init_params.delegate = mock_cast_wc_delegate_.AsWeakPtr(); + init_params.is_root_window = true; + cast_web_contents_ = std::make_unique<CastWebContentsImpl>(web_contents_.get(), init_params); mock_cast_wc_observer_.Observe(cast_web_contents_.get());
diff --git a/chromecast/browser/cast_web_contents_impl.cc b/chromecast/browser/cast_web_contents_impl.cc index 5b63dea..20d4550 100644 --- a/chromecast/browser/cast_web_contents_impl.cc +++ b/chromecast/browser/cast_web_contents_impl.cc
@@ -225,11 +225,6 @@ media_blocker_->EnableBackgroundVideoPlayback(enabled); } -void CastWebContentsImpl::SetDelegate(CastWebContents::Delegate* delegate) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - delegate_ = delegate; -} - void CastWebContentsImpl::AllowWebAndMojoWebUiBindings() { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); content::RenderViewHost* rvh = web_contents_->GetRenderViewHost(); @@ -411,6 +406,12 @@ mojo::ScopedMessagePipeHandle* interface_pipe) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + if (!delegate_) { + // Don't let the page bind any more interfaces at this point, since the + // owning client has been torn down. This is a cheap trick so that all of + // the interfaces don't have to provide binder callbacks with WeakPtr. + return; + } if (binder_registry_.TryBindInterface(interface_name, interface_pipe)) { return; } @@ -712,11 +713,12 @@ content::WebContents* inner_web_contents) { if (!handle_inner_contents_ || !delegate_) return; - auto result = inner_contents_.insert(std::make_unique<CastWebContentsImpl>( - inner_web_contents, - InitParams{nullptr, enabled_for_dev_, false /* use_cma_renderer */, - false /* is_root_window */, false /* handle_inner_contents */, - false /* use_media_blocker */, view_background_color_})); + InitParams params; + params.delegate = delegate_; + params.enabled_for_dev = enabled_for_dev_; + params.background_color = view_background_color_; + auto result = inner_contents_.insert( + std::make_unique<CastWebContentsImpl>(inner_web_contents, params)); delegate_->InnerContentsCreated(result.first->get(), this); }
diff --git a/chromecast/browser/cast_web_contents_impl.h b/chromecast/browser/cast_web_contents_impl.h index 9eb6604..c7b671c 100644 --- a/chromecast/browser/cast_web_contents_impl.h +++ b/chromecast/browser/cast_web_contents_impl.h
@@ -45,7 +45,6 @@ // CastWebContents implementation: int tab_id() const override; - void SetDelegate(Delegate* delegate) override; void AddRendererFeatures(std::vector<RendererFeature> features) override; void AllowWebAndMojoWebUiBindings() override; void ClearRenderWidgetHostView() override; @@ -67,8 +66,6 @@ const std::string& target_origin, const std::string& data, std::vector<mojo::ScopedMessagePipeHandle> channels) override; - - // Observer interface: void AddObserver(Observer* observer) override; void RemoveObserver(Observer* observer) override; @@ -141,7 +138,7 @@ std::vector<chromecast::shell::mojom::FeaturePtr> GetRendererFeatures(); content::WebContents* web_contents_; - Delegate* delegate_; + base::WeakPtr<Delegate> delegate_; PageState page_state_; PageState last_state_; const bool enabled_for_dev_; @@ -168,10 +165,10 @@ base::ObserverList<Observer>::Unchecked observer_list_; - const scoped_refptr<base::SequencedTaskRunner> task_runner_; - service_manager::BinderRegistry binder_registry_; + const scoped_refptr<base::SequencedTaskRunner> task_runner_; + // Map of InterfaceSet -> InterfaceProvider pointer. base::flat_map<InterfaceSet, service_manager::InterfaceProvider*> interface_providers_map_;
diff --git a/chromecast/browser/cast_web_contents_manager.cc b/chromecast/browser/cast_web_contents_manager.cc deleted file mode 100644 index 944c202..0000000 --- a/chromecast/browser/cast_web_contents_manager.cc +++ /dev/null
@@ -1,99 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chromecast/browser/cast_web_contents_manager.h" - -#include <algorithm> -#include <memory> - -#include "base/bind.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/sequenced_task_runner.h" -#include "base/stl_util.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/time/time.h" -#include "chromecast/browser/cast_web_view_default.h" -#include "chromecast/browser/cast_web_view_factory.h" -#include "chromecast/chromecast_buildflags.h" -#include "content/public/browser/media_session.h" -#include "content/public/browser/site_instance.h" -#include "content/public/browser/web_contents.h" - -namespace chromecast { - -CastWebContentsManager::CastWebContentsManager( - content::BrowserContext* browser_context, - CastWebViewFactory* web_view_factory, - CastWindowManager* window_manager) - : browser_context_(browser_context), - web_view_factory_(web_view_factory), - window_manager_(window_manager), - task_runner_(base::SequencedTaskRunnerHandle::Get()), - weak_factory_(this) { - DCHECK(browser_context_); - DCHECK(web_view_factory_); - DCHECK(task_runner_); -} - -CastWebContentsManager::~CastWebContentsManager() = default; - -std::unique_ptr<CastWebView> CastWebContentsManager::CreateWebView( - const CastWebView::CreateParams& params, - scoped_refptr<content::SiteInstance> site_instance, - const GURL& initial_url) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return web_view_factory_->CreateWebView( - params, this, std::move(site_instance), initial_url); -} - -std::unique_ptr<CastWebView> CastWebContentsManager::CreateWebView( - const CastWebView::CreateParams& params, - const GURL& initial_url) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - return web_view_factory_->CreateWebView( - params, this, - content::SiteInstance::CreateForURL(browser_context_, initial_url), - initial_url); -} - -void CastWebContentsManager::DelayWebContentsDeletion( - std::unique_ptr<content::WebContents> web_contents, - base::TimeDelta time_delta) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(web_contents); - if (time_delta <= base::TimeDelta()) { - LOG(INFO) << "Deleting WebContents for " << web_contents->GetVisibleURL(); - web_contents.reset(); - return; - } - auto* web_contents_ptr = web_contents.get(); - // Suspend the MediaSession to free up media resources for the next content - // window. - content::MediaSession::Get(web_contents_ptr) - ->Suspend(content::MediaSession::SuspendType::kSystem); - LOG(INFO) << "WebContents for " << web_contents->GetVisibleURL() - << " will be deleted in " << time_delta.InMilliseconds() - << " milliseconds."; - expiring_web_contents_.insert(std::move(web_contents)); - task_runner_->PostDelayedTask( - FROM_HERE, - base::BindOnce(&CastWebContentsManager::DeleteWebContents, - weak_factory_.GetWeakPtr(), web_contents_ptr), - time_delta); -} - -void CastWebContentsManager::DeleteWebContents( - content::WebContents* web_contents) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - DCHECK(web_contents); - LOG(INFO) << "Deleting WebContents for " << web_contents->GetVisibleURL(); - base::EraseIf( - expiring_web_contents_, - [web_contents](const std::unique_ptr<content::WebContents>& ptr) { - return ptr.get() == web_contents; - }); -} - -} // namespace chromecast
diff --git a/chromecast/browser/cast_web_contents_manager.h b/chromecast/browser/cast_web_contents_manager.h deleted file mode 100644 index 3aaedd4..0000000 --- a/chromecast/browser/cast_web_contents_manager.h +++ /dev/null
@@ -1,79 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROMECAST_BROWSER_CAST_WEB_CONTENTS_MANAGER_H_ -#define CHROMECAST_BROWSER_CAST_WEB_CONTENTS_MANAGER_H_ - -#include <memory> - -#include "base/containers/flat_set.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/sequence_checker.h" -#include "chromecast/browser/cast_web_view.h" - -namespace base { -class SequencedTaskRunner; -} // namespace base - -namespace content { -class BrowserContext; -class WebContents; -} // namespace content - -namespace chromecast { - -class CastWebViewFactory; -class CastWindowManager; - -// This class dispenses CastWebView objects which are used to wrap WebContents -// in cast_shell. This class can take ownership of a WebContents instance when -// the page is in the process of tearing down; we cannot simply post a delayed -// task since WebContents may try to use browser objects that get deleted as a -// result of browser shutdown. -class CastWebContentsManager { - public: - CastWebContentsManager(content::BrowserContext* browser_context, - CastWebViewFactory* web_view_factory, - CastWindowManager* window_manager); - ~CastWebContentsManager(); - - std::unique_ptr<CastWebView> CreateWebView( - const CastWebView::CreateParams& params, - scoped_refptr<content::SiteInstance> site_instance, - const GURL& initial_url); - - std::unique_ptr<CastWebView> CreateWebView( - const CastWebView::CreateParams& params, - const GURL& initial_url); - - std::unique_ptr<CastContentWindow> CreateWindow( - const CastContentWindow::CreateParams& params); - - // Take ownership of |web_contents| and delete after |time_delta|, or sooner - // if necessary. - void DelayWebContentsDeletion( - std::unique_ptr<content::WebContents> web_contents, - base::TimeDelta time_delta); - - private: - void DeleteWebContents(content::WebContents* web_contents); - - content::BrowserContext* const browser_context_; - CastWebViewFactory* const web_view_factory_; - CastWindowManager* const window_manager_; - base::flat_set<std::unique_ptr<content::WebContents>> expiring_web_contents_; - - const scoped_refptr<base::SequencedTaskRunner> task_runner_; - - SEQUENCE_CHECKER(sequence_checker_); - base::WeakPtrFactory<CastWebContentsManager> weak_factory_; - - DISALLOW_COPY_AND_ASSIGN(CastWebContentsManager); -}; - -} // namespace chromecast - -#endif // CHROMECAST_BROWSER_CAST_WEB_CONTENTS_MANAGER_H_
diff --git a/chromecast/browser/cast_web_service.cc b/chromecast/browser/cast_web_service.cc new file mode 100644 index 0000000..0897edf3 --- /dev/null +++ b/chromecast/browser/cast_web_service.cc
@@ -0,0 +1,104 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/browser/cast_web_service.h" + +#include <algorithm> +#include <memory> + +#include "base/bind.h" +#include "base/location.h" +#include "base/macros.h" +#include "base/sequenced_task_runner.h" +#include "base/stl_util.h" +#include "base/threading/sequenced_task_runner_handle.h" +#include "base/time/time.h" +#include "chromecast/browser/cast_web_view_default.h" +#include "chromecast/browser/cast_web_view_factory.h" +#include "chromecast/chromecast_buildflags.h" +#include "content/public/browser/media_session.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/web_contents.h" + +namespace chromecast { + +CastWebService::CastWebService(content::BrowserContext* browser_context, + CastWebViewFactory* web_view_factory, + CastWindowManager* window_manager) + : browser_context_(browser_context), + web_view_factory_(web_view_factory), + window_manager_(window_manager), + task_runner_(base::SequencedTaskRunnerHandle::Get()), + weak_factory_(this) { + DCHECK(browser_context_); + DCHECK(web_view_factory_); + DCHECK(task_runner_); + weak_ptr_ = weak_factory_.GetWeakPtr(); +} + +CastWebService::~CastWebService() = default; + +CastWebView::Scoped CastWebService::CreateWebView( + const CastWebView::CreateParams& params, + scoped_refptr<content::SiteInstance> site_instance, + const GURL& initial_url) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto web_view = web_view_factory_->CreateWebView( + params, this, std::move(site_instance), initial_url); + CastWebView::Scoped scoped(web_view.get(), [this](CastWebView* web_view) { + OwnerDestroyed(web_view); + }); + web_views_.insert(std::move(web_view)); + return scoped; +} + +CastWebView::Scoped CastWebService::CreateWebView( + const CastWebView::CreateParams& params, + const GURL& initial_url) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + auto web_view = web_view_factory_->CreateWebView( + params, this, + content::SiteInstance::CreateForURL(browser_context_, initial_url), + initial_url); + CastWebView::Scoped scoped(web_view.get(), [this](CastWebView* web_view) { + OwnerDestroyed(web_view); + }); + web_views_.insert(std::move(web_view)); + return scoped; +} + +void CastWebService::OwnerDestroyed(CastWebView* web_view) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + content::WebContents* web_contents = web_view->web_contents(); + GURL url; + if (web_contents) { + url = web_contents->GetVisibleURL(); + // Suspend the MediaSession to free up media resources for the next content + // window. + content::MediaSession::Get(web_contents) + ->Suspend(content::MediaSession::SuspendType::kSystem); + } + auto delay = web_view->shutdown_delay(); + if (delay <= base::TimeDelta()) { + LOG(INFO) << "Immediately deleting CastWebView for " << url; + DeleteWebView(web_view); + return; + } + LOG(INFO) << "Deleting CastWebView for " << url << " in " + << delay.InMilliseconds() << " milliseconds."; + task_runner_->PostDelayedTask( + FROM_HERE, + base::BindOnce(&CastWebService::DeleteWebView, weak_ptr_, web_view), + delay); +} + +void CastWebService::DeleteWebView(CastWebView* web_view) { + LOG(INFO) << "Deleting CastWebView."; + base::EraseIf(web_views_, + [web_view](const std::unique_ptr<CastWebView>& ptr) { + return ptr.get() == web_view; + }); +} + +} // namespace chromecast
diff --git a/chromecast/browser/cast_web_service.h b/chromecast/browser/cast_web_service.h new file mode 100644 index 0000000..c2aa303e --- /dev/null +++ b/chromecast/browser/cast_web_service.h
@@ -0,0 +1,73 @@ +// 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. + +#ifndef CHROMECAST_BROWSER_CAST_WEB_SERVICE_H_ +#define CHROMECAST_BROWSER_CAST_WEB_SERVICE_H_ + +#include <memory> + +#include "base/containers/flat_set.h" +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "base/sequence_checker.h" +#include "chromecast/browser/cast_web_view.h" + +namespace base { +class SequencedTaskRunner; +} // namespace base + +namespace content { +class BrowserContext; +} // namespace content + +namespace chromecast { + +class CastWebViewFactory; +class CastWindowManager; + +// This class dispenses CastWebView objects which are used to wrap WebContents +// in cast_shell. This class temporarily takes ownership of CastWebViews when +// they go out of scope, allowing us to keep the pages alive for extra time if +// needed. CastWebService allows us to synchronously destroy all pages when the +// system is shutting down, preventing use of freed browser resources. +class CastWebService { + public: + CastWebService(content::BrowserContext* browser_context, + CastWebViewFactory* web_view_factory, + CastWindowManager* window_manager); + ~CastWebService(); + + CastWebView::Scoped CreateWebView( + const CastWebView::CreateParams& params, + scoped_refptr<content::SiteInstance> site_instance, + const GURL& initial_url); + + CastWebView::Scoped CreateWebView(const CastWebView::CreateParams& params, + const GURL& initial_url); + + std::unique_ptr<CastContentWindow> CreateWindow( + const CastContentWindow::CreateParams& params); + + private: + void OwnerDestroyed(CastWebView* web_view); + void DeleteWebView(CastWebView* web_view); + + content::BrowserContext* const browser_context_; + CastWebViewFactory* const web_view_factory_; + CastWindowManager* const window_manager_; + base::flat_set<std::unique_ptr<CastWebView>> web_views_; + + const scoped_refptr<base::SequencedTaskRunner> task_runner_; + base::WeakPtr<CastWebService> weak_ptr_; + + SEQUENCE_CHECKER(sequence_checker_); + base::WeakPtrFactory<CastWebService> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(CastWebService); +}; + +} // namespace chromecast + +#endif // CHROMECAST_BROWSER_CAST_WEB_SERVICE_H_
diff --git a/chromecast/browser/cast_web_contents_manager_aura.cc b/chromecast/browser/cast_web_service_aura.cc similarity index 76% rename from chromecast/browser/cast_web_contents_manager_aura.cc rename to chromecast/browser/cast_web_service_aura.cc index e4b51da..62b5189 100644 --- a/chromecast/browser/cast_web_contents_manager_aura.cc +++ b/chromecast/browser/cast_web_service_aura.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chromecast/browser/cast_web_contents_manager.h" +#include "chromecast/browser/cast_web_service.h" #include <memory> @@ -10,7 +10,7 @@ namespace chromecast { -std::unique_ptr<CastContentWindow> CastWebContentsManager::CreateWindow( +std::unique_ptr<CastContentWindow> CastWebService::CreateWindow( const CastContentWindow::CreateParams& params) { return std::make_unique<CastContentWindowAura>(params, window_manager_); }
diff --git a/chromecast/browser/cast_web_view.cc b/chromecast/browser/cast_web_view.cc index e74bea8..5f6e9d4d 100644 --- a/chromecast/browser/cast_web_view.cc +++ b/chromecast/browser/cast_web_view.cc
@@ -13,7 +13,9 @@ return nullptr; } -CastWebView::CastWebView() {} +CastWebView::CastWebView(const CreateParams& create_params) + : delegate_(create_params.delegate), + shutdown_delay_(create_params.shutdown_delay) {} CastWebView::~CastWebView() { for (Observer& observer : observer_list_) { @@ -21,6 +23,11 @@ } } +void CastWebView::ForceClose() { + shutdown_delay_ = base::TimeDelta(); + ClosePage(); +} + void CastWebView::AddObserver(CastWebView::Observer* observer) { observer_list_.AddObserver(observer); } @@ -29,10 +36,8 @@ observer_list_.RemoveObserver(observer); } -CastWebView::CreateParams::CreateParams() {} - +CastWebView::CreateParams::CreateParams() = default; CastWebView::CreateParams::CreateParams(const CreateParams& other) = default; - CastWebView::CreateParams::~CreateParams() = default; } // namespace chromecast
diff --git a/chromecast/browser/cast_web_view.h b/chromecast/browser/cast_web_view.h index 97ed5697..6ca15a3 100644 --- a/chromecast/browser/cast_web_view.h +++ b/chromecast/browser/cast_web_view.h
@@ -49,11 +49,19 @@ virtual ~Observer() {} }; + // When the unique_ptr is reset, the CastWebView may not necessarily be + // destroyed. In some cases ownership will be passed to the CastWebService, + // which eventually handles destruction. + using Scoped = + std::unique_ptr<CastWebView, std::function<void(CastWebView*)>>; + // The parameters used to create a CastWebView instance. Passed to - // CastWebContentsManager::CreateWebView(). + // CastWebService::CreateWebView(). struct CreateParams { - // The delegate for the CastWebView. Must be non-null. - Delegate* delegate = nullptr; + // The delegate for the CastWebView. Must be non-null. If the delegate is + // destroyed before CastWebView, the WeakPtr will be invalidated on the main + // UI thread. + base::WeakPtr<Delegate> delegate = nullptr; // Parameters for initializing CastWebContents. These will be passed as-is // to a CastWebContents instance, which should be used by all CastWebView @@ -82,12 +90,17 @@ // of console log messages. std::string log_prefix = ""; + // Delays CastWebView deletion after CastWebView::Scoped is reset. The + // default value is zero, which means the CastWebView will be deleted + // immediately and synchronously. + base::TimeDelta shutdown_delay = base::TimeDelta(); + CreateParams(); CreateParams(const CreateParams& other); ~CreateParams(); }; - CastWebView(); + explicit CastWebView(const CreateParams& create_params); virtual ~CastWebView(); virtual CastContentWindow* window() const = 0; @@ -96,6 +109,8 @@ virtual CastWebContents* cast_web_contents() = 0; + base::TimeDelta shutdown_delay() const { return shutdown_delay_; } + // Navigates to |url|. The loaded page will be preloaded if MakeVisible has // not been called on the object. virtual void LoadUrl(GURL url) = 0; @@ -103,8 +118,12 @@ // Begins the close process for this page (ie. triggering document.onunload). // A consumer of the class can be notified when the process has been finished // via Delegate::OnPageStopped(). The page will be torn down after - // |shutdown_delay| has elapsed, or sooner if required. - virtual void ClosePage(const base::TimeDelta& shutdown_delay) = 0; + // |CreateParams::shutdown_delay| has elapsed, or immediately if the browser + // is shutting down. + virtual void ClosePage() = 0; + + // Closes the page immediately, ignoring |CreateParams::shutdown_delay|. + void ForceClose(); // Adds the page to the window manager and makes it visible to the user if // |is_visible| is true. |z_order| determines how this window is layered in @@ -124,7 +143,12 @@ void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); + protected: + base::WeakPtr<Delegate> delegate_; + private: + base::TimeDelta shutdown_delay_; + base::ObserverList<Observer>::Unchecked observer_list_; DISALLOW_COPY_AND_ASSIGN(CastWebView);
diff --git a/chromecast/browser/cast_web_view_default.cc b/chromecast/browser/cast_web_view_default.cc index 44f1584..fa9b18c 100644 --- a/chromecast/browser/cast_web_view_default.cc +++ b/chromecast/browser/cast_web_view_default.cc
@@ -15,7 +15,7 @@ #include "chromecast/base/chromecast_switches.h" #include "chromecast/base/metrics/cast_metrics_helper.h" #include "chromecast/browser/cast_browser_process.h" -#include "chromecast/browser/cast_web_contents_manager.h" +#include "chromecast/browser/cast_web_service.h" #include "chromecast/chromecast_buildflags.h" #include "content/public/browser/media_capture_devices.h" #include "content/public/browser/media_session.h" @@ -52,14 +52,14 @@ CastWebViewDefault::CastWebViewDefault( const CreateParams& params, - CastWebContentsManager* web_contents_manager, + CastWebService* web_service, content::BrowserContext* browser_context, scoped_refptr<content::SiteInstance> site_instance, std::unique_ptr<CastContentWindow> cast_content_window) - : web_contents_manager_(web_contents_manager), + : CastWebView(params), + web_service_(web_service), browser_context_(browser_context), site_instance_(std::move(site_instance)), - delegate_(params.delegate), activity_id_(params.activity_id), session_id_(params.window_params.session_id), sdk_version_(params.sdk_version), @@ -69,10 +69,9 @@ cast_web_contents_(web_contents_.get(), params.web_contents_params), window_(cast_content_window ? std::move(cast_content_window) - : web_contents_manager->CreateWindow(params.window_params)), + : web_service->CreateWindow(params.window_params)), resize_window_when_navigation_starts_(true) { - DCHECK(delegate_); - DCHECK(web_contents_manager_); + DCHECK(web_service_); DCHECK(browser_context_); DCHECK(window_); content::WebContentsObserver::Observe(web_contents_.get()); @@ -109,8 +108,7 @@ cast_web_contents_.LoadUrl(url); } -void CastWebViewDefault::ClosePage(const base::TimeDelta& shutdown_delay) { - shutdown_delay_ = shutdown_delay; +void CastWebViewDefault::ClosePage() { content::WebContentsObserver::Observe(nullptr); cast_web_contents_.ClosePage(); } @@ -118,13 +116,6 @@ void CastWebViewDefault::CloseContents(content::WebContents* source) { DCHECK_EQ(source, web_contents_.get()); window_.reset(); // Window destructor requires live web_contents on Android. - if (!shutdown_delay_.is_zero()) { - // We need to delay the deletion of web_contents_ to give (and guarantee) - // the renderer enough time to finish 'onunload' handler (but we don't want - // to wait any longer than that to delay the starting of next app). - web_contents_manager_->DelayWebContentsDeletion(std::move(web_contents_), - shutdown_delay_); - } // This will signal to the owner that |web_contents_| is no longer in use, // permitting the owner to tear down. cast_web_contents_.Stop(net::OK); @@ -269,7 +260,10 @@ CastWebViewDefault::RunBluetoothChooser( content::RenderFrameHost* frame, const content::BluetoothChooser::EventHandler& event_handler) { - auto chooser = delegate_->RunBluetoothChooser(frame, event_handler); + std::unique_ptr<content::BluetoothChooser> chooser; + if (delegate_) { + chooser = delegate_->RunBluetoothChooser(frame, event_handler); + } return chooser ? std::move(chooser) : WebContentsDelegate::RunBluetoothChooser(frame, event_handler);
diff --git a/chromecast/browser/cast_web_view_default.h b/chromecast/browser/cast_web_view_default.h index 5aaa091..becf4006 100644 --- a/chromecast/browser/cast_web_view_default.h +++ b/chromecast/browser/cast_web_view_default.h
@@ -25,19 +25,19 @@ namespace chromecast { -class CastWebContentsManager; +class CastWebService; // A simplified interface for loading and displaying WebContents in cast_shell. class CastWebViewDefault : public CastWebView, content::WebContentsObserver, content::WebContentsDelegate { public: - // |web_contents_manager| and |browser_context| should outlive this object. - // If |cast_content_window| is not provided, an instance will be constructed - // from |web_contents_manager|. + // |web_service| and |browser_context| should outlive this object. If + // |cast_content_window| is not provided, an instance will be constructed from + // |web_service|. CastWebViewDefault( const CreateParams& params, - CastWebContentsManager* web_contents_manager, + CastWebService* web_service, content::BrowserContext* browser_context, scoped_refptr<content::SiteInstance> site_instance, std::unique_ptr<CastContentWindow> cast_content_window = nullptr); @@ -48,7 +48,7 @@ content::WebContents* web_contents() const override; CastWebContents* cast_web_contents() override; void LoadUrl(GURL url) override; - void ClosePage(const base::TimeDelta& shutdown_delay) override; + void ClosePage() override; void InitializeWindow(mojom::ZOrder z_order, VisibilityPriority initial_priority) override; void GrantScreenAccess() override; @@ -85,11 +85,10 @@ const url::Origin& origin, const GURL& resource_url) override; - CastWebContentsManager* const web_contents_manager_; + CastWebService* const web_service_; content::BrowserContext* const browser_context_; const scoped_refptr<content::SiteInstance> site_instance_; - Delegate* const delegate_; const std::string activity_id_; const std::string session_id_; const std::string sdk_version_; @@ -100,7 +99,6 @@ CastWebContentsImpl cast_web_contents_; std::unique_ptr<CastContentWindow> window_; bool resize_window_when_navigation_starts_; - base::TimeDelta shutdown_delay_; DISALLOW_COPY_AND_ASSIGN(CastWebViewDefault); };
diff --git a/chromecast/browser/cast_web_view_factory.cc b/chromecast/browser/cast_web_view_factory.cc index 566487d..0b9eb9d5c 100644 --- a/chromecast/browser/cast_web_view_factory.cc +++ b/chromecast/browser/cast_web_view_factory.cc
@@ -22,12 +22,12 @@ std::unique_ptr<CastWebView> CastWebViewFactory::CreateWebView( const CastWebView::CreateParams& params, - CastWebContentsManager* web_contents_manager, + CastWebService* web_service, scoped_refptr<content::SiteInstance> site_instance, const GURL& initial_url) { std::unique_ptr<CastWebView> webview; webview = std::make_unique<CastWebViewDefault>( - params, web_contents_manager, browser_context_, site_instance); + params, web_service, browser_context_, site_instance); if (webview) { webview->AddObserver(this); }
diff --git a/chromecast/browser/cast_web_view_factory.h b/chromecast/browser/cast_web_view_factory.h index 65cbe07..6fe95e9 100644 --- a/chromecast/browser/cast_web_view_factory.h +++ b/chromecast/browser/cast_web_view_factory.h
@@ -21,7 +21,7 @@ namespace chromecast { -class CastWebContentsManager; +class CastWebService; class CastWebViewFactory : public CastWebView::Observer { public: @@ -30,7 +30,7 @@ virtual std::unique_ptr<CastWebView> CreateWebView( const CastWebView::CreateParams& params, - CastWebContentsManager* web_contents_manager, + CastWebService* web_service, scoped_refptr<content::SiteInstance> site_instance, const GURL& initial_url);
diff --git a/chromecast/browser/service/cast_service_simple.cc b/chromecast/browser/service/cast_service_simple.cc index 0bbdc21..3f7ea0ab 100644 --- a/chromecast/browser/service/cast_service_simple.cc +++ b/chromecast/browser/service/cast_service_simple.cc
@@ -11,7 +11,7 @@ #include "base/time/time.h" #include "chromecast/browser/cast_browser_process.h" #include "chromecast/browser/cast_content_window.h" -#include "chromecast/browser/cast_web_contents_manager.h" +#include "chromecast/browser/cast_web_service.h" #include "chromecast/browser/cast_web_view_factory.h" #include "content/public/browser/web_contents.h" #include "content/public/common/content_switches.h" @@ -44,10 +44,9 @@ CastWindowManager* window_manager) : CastService(browser_context, pref_service), web_view_factory_(std::make_unique<CastWebViewFactory>(browser_context)), - web_contents_manager_( - std::make_unique<CastWebContentsManager>(browser_context, - web_view_factory_.get(), - window_manager)) { + web_service_(std::make_unique<CastWebService>(browser_context, + web_view_factory_.get(), + window_manager)) { shell::CastBrowserProcess::GetInstance()->SetWebViewFactory( web_view_factory_.get()); } @@ -68,13 +67,13 @@ } CastWebView::CreateParams params; - params.delegate = this; - params.web_contents_params.delegate = this; + params.delegate = weak_factory_.GetWeakPtr(); + params.web_contents_params.delegate = weak_factory_.GetWeakPtr(); params.web_contents_params.enabled_for_dev = true; - params.window_params.delegate = this; + params.window_params.delegate = weak_factory_.GetWeakPtr(); cast_web_view_ = - web_contents_manager_->CreateWebView(params, nullptr, /* site_instance */ - GURL() /* initial_url */); + web_service_->CreateWebView(params, nullptr, /* site_instance */ + GURL() /* initial_url */); cast_web_view_->LoadUrl(startup_url_); cast_web_view_->GrantScreenAccess(); cast_web_view_->InitializeWindow( @@ -84,7 +83,7 @@ void CastServiceSimple::StopInternal() { if (cast_web_view_) { - cast_web_view_->ClosePage(base::TimeDelta()); + cast_web_view_->ClosePage(); } cast_web_view_.reset(); }
diff --git a/chromecast/browser/service/cast_service_simple.h b/chromecast/browser/service/cast_service_simple.h index 71c13fc..461a2707 100644 --- a/chromecast/browser/service/cast_service_simple.h +++ b/chromecast/browser/service/cast_service_simple.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "chromecast/browser/cast_content_window.h" #include "chromecast/browser/cast_web_view.h" #include "chromecast/service/cast_service.h" @@ -15,7 +16,7 @@ namespace chromecast { -class CastWebContentsManager; +class CastWebService; class CastWebViewFactory; class CastWindowManager; @@ -44,10 +45,11 @@ private: const std::unique_ptr<CastWebViewFactory> web_view_factory_; - const std::unique_ptr<CastWebContentsManager> web_contents_manager_; - std::unique_ptr<CastWebView> cast_web_view_; + const std::unique_ptr<CastWebService> web_service_; + CastWebView::Scoped cast_web_view_; GURL startup_url_; + base::WeakPtrFactory<CastServiceSimple> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(CastServiceSimple); };
diff --git a/chromecast/browser/test/cast_browser_test.cc b/chromecast/browser/test/cast_browser_test.cc index 4ca3862..5f9300e4 100644 --- a/chromecast/browser/test/cast_browser_test.cc +++ b/chromecast/browser/test/cast_browser_test.cc
@@ -12,7 +12,7 @@ #include "chromecast/browser/cast_browser_context.h" #include "chromecast/browser/cast_browser_process.h" #include "chromecast/browser/cast_content_window.h" -#include "chromecast/browser/cast_web_contents_manager.h" +#include "chromecast/browser/cast_web_service.h" #include "chromecast/browser/cast_web_view_factory.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" @@ -47,7 +47,7 @@ metrics::CastMetricsHelper::GetInstance()->SetDummySessionIdForTesting(); web_view_factory_ = std::make_unique<CastWebViewFactory>( CastBrowserProcess::GetInstance()->browser_context()); - web_contents_manager_ = std::make_unique<CastWebContentsManager>( + web_service_ = std::make_unique<CastWebService>( CastBrowserProcess::GetInstance()->browser_context(), web_view_factory_.get(), nullptr /* window_manager */); } @@ -58,14 +58,14 @@ content::WebContents* CastBrowserTest::CreateWebView() { CastWebView::CreateParams params; - params.delegate = this; - params.web_contents_params.delegate = this; + params.delegate = weak_factory_.GetWeakPtr(); + params.web_contents_params.delegate = weak_factory_.GetWeakPtr(); params.web_contents_params.use_cma_renderer = true; params.web_contents_params.enabled_for_dev = true; - params.window_params.delegate = this; + params.window_params.delegate = weak_factory_.GetWeakPtr(); cast_web_view_ = - web_contents_manager_->CreateWebView(params, nullptr, /* site_instance */ - GURL() /* initial_url */); + web_service_->CreateWebView(params, nullptr, /* site_instance */ + GURL() /* initial_url */); return cast_web_view_->web_contents(); }
diff --git a/chromecast/browser/test/cast_browser_test.h b/chromecast/browser/test/cast_browser_test.h index dfb64ad..1bcad42 100644 --- a/chromecast/browser/test/cast_browser_test.h +++ b/chromecast/browser/test/cast_browser_test.h
@@ -8,6 +8,7 @@ #include <memory> #include "base/macros.h" +#include "base/memory/weak_ptr.h" #include "chromecast/browser/cast_web_view.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_base.h" @@ -18,7 +19,7 @@ namespace chromecast { -class CastWebContentsManager; +class CastWebService; class CastWebViewFactory; namespace shell { @@ -28,7 +29,8 @@ // case, then shuts down the entire shell. // Note that this process takes 7-10 seconds per test case on Chromecast, so // fewer test cases with more assertions are preferable. -class CastBrowserTest : public content::BrowserTestBase, CastWebView::Delegate { +class CastBrowserTest : public content::BrowserTestBase, + public CastWebView::Delegate { protected: CastBrowserTest(); ~CastBrowserTest() override; @@ -51,9 +53,10 @@ std::string GetId() override; std::unique_ptr<CastWebViewFactory> web_view_factory_; - std::unique_ptr<CastWebContentsManager> web_contents_manager_; - std::unique_ptr<CastWebView> cast_web_view_; + std::unique_ptr<CastWebService> web_service_; + CastWebView::Scoped cast_web_view_; + base::WeakPtrFactory<CastBrowserTest> weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(CastBrowserTest); };
diff --git a/chromecast/browser/webview/webview_controller.cc b/chromecast/browser/webview/webview_controller.cc index ae3626eb..8d83a468 100644 --- a/chromecast/browser/webview/webview_controller.cc +++ b/chromecast/browser/webview/webview_controller.cc
@@ -55,7 +55,7 @@ CastWebContents::InitParams cast_contents_init; cast_contents_init.is_root_window = true; cast_contents_init.enabled_for_dev = CAST_IS_DEBUG_BUILD(); - cast_contents_init.delegate = this; + cast_contents_init.delegate = weak_ptr_factory_.GetWeakPtr(); cast_web_contents_ = std::make_unique<CastWebContentsImpl>( contents_.get(), cast_contents_init); cast_web_contents_->AddObserver(this);
diff --git a/chromeos/dbus/power/power_manager_client.cc b/chromeos/dbus/power/power_manager_client.cc index 213e531..7e7420a 100644 --- a/chromeos/dbus/power/power_manager_client.cc +++ b/chromeos/dbus/power/power_manager_client.cc
@@ -178,6 +178,8 @@ const std::map<const char*, SignalMethod> kSignalMethods = { {power_manager::kScreenBrightnessChangedSignal, &PowerManagerClientImpl::ScreenBrightnessChangedReceived}, + {power_manager::kAmbientColorTemperatureChangedSignal, + &PowerManagerClientImpl::AmbientColorTemperatureChangedReceived}, {power_manager::kKeyboardBrightnessChangedSignal, &PowerManagerClientImpl::KeyboardBrightnessChangedReceived}, {power_manager::kScreenIdleStateChangedSignal, @@ -617,6 +619,20 @@ observer.ScreenBrightnessChanged(proto); } + void AmbientColorTemperatureChangedReceived(dbus::Signal* signal) { + dbus::MessageReader reader(signal); + int32_t color_temperature = 0; + if (!reader.PopInt32(&color_temperature)) { + POWER_LOG(ERROR) << "Unable to decode read ambient color from " + << power_manager::kAmbientColorTemperatureChangedSignal + << " signal"; + return; + } + + for (auto& observer : observers_) + observer.AmbientColorChanged(color_temperature); + } + void KeyboardBrightnessChangedReceived(dbus::Signal* signal) { dbus::MessageReader reader(signal); power_manager::BacklightBrightnessChange proto;
diff --git a/chromeos/dbus/power/power_manager_client.h b/chromeos/dbus/power/power_manager_client.h index 72a95126..d2c3a3f9 100644 --- a/chromeos/dbus/power/power_manager_client.h +++ b/chromeos/dbus/power/power_manager_client.h
@@ -82,6 +82,9 @@ virtual void ScreenBrightnessChanged( const power_manager::BacklightBrightnessChange& change) {} + // Called when the ambient light changed. + virtual void AmbientColorChanged(const int32_t color_temperature) {} + // Called when the keyboard brightness is changed. virtual void KeyboardBrightnessChanged( const power_manager::BacklightBrightnessChange& change) {}
diff --git a/chromeos/dbus/power/power_manager_client_unittest.cc b/chromeos/dbus/power/power_manager_client_unittest.cc index 7bc2e89..f96d57b6 100644 --- a/chromeos/dbus/power/power_manager_client_unittest.cc +++ b/chromeos/dbus/power/power_manager_client_unittest.cc
@@ -96,6 +96,9 @@ const base::UnguessableToken& block_suspend_token() const { return block_suspend_token_; } + int32_t ambient_color_temperature() const { + return ambient_color_temperature_; + } void set_should_block_suspend(bool take_callback) { should_block_suspend_ = take_callback; @@ -135,6 +138,9 @@ if (run_unblock_suspend_immediately_) CHECK(UnblockSuspend()); } + void AmbientColorChanged(const int32_t color_temperature) override { + ambient_color_temperature_ = color_temperature; + } private: PowerManagerClient* client_; // Not owned. @@ -157,6 +163,8 @@ // When non-empty, the token for the outstanding block-suspend registration. base::UnguessableToken block_suspend_token_; + // Ambient color temperature + int32_t ambient_color_temperature_ = 0; DISALLOW_COPY_AND_ASSIGN(TestObserver); }; @@ -592,4 +600,17 @@ EmitSuspendDoneSignal(kSuspendId); } +// Tests that observers are notified about changes in ambient color temperature. +TEST_F(PowerManagerClientTest, ChangeAmbientColorTemperature) { + TestObserver observer(client_); + + constexpr int32_t kTemperature = 6500; + dbus::Signal signal(kInterface, + power_manager::kAmbientColorTemperatureChangedSignal); + dbus::MessageWriter(&signal).AppendInt32(kTemperature); + EmitSignal(&signal); + + EXPECT_EQ(kTemperature, observer.ambient_color_temperature()); +} + } // namespace chromeos
diff --git a/chromeos/profiles/airmont.afdo.newest.txt b/chromeos/profiles/airmont.afdo.newest.txt index 885dc947..b342292 100644 --- a/chromeos/profiles/airmont.afdo.newest.txt +++ b/chromeos/profiles/airmont.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-airmont-80-3945.13-1572864139-benchmark-80.0.3960.0-r1-redacted.afdo.xz \ No newline at end of file +chromeos-chrome-amd64-airmont-80-3945.13-1572864139-benchmark-80.0.3961.0-r1-redacted.afdo.xz \ No newline at end of file
diff --git a/chromeos/profiles/broadwell.afdo.newest.txt b/chromeos/profiles/broadwell.afdo.newest.txt index acade739..5da2d2c 100644 --- a/chromeos/profiles/broadwell.afdo.newest.txt +++ b/chromeos/profiles/broadwell.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-broadwell-80-3943.1-1572873357-benchmark-80.0.3960.0-r1-redacted.afdo.xz \ No newline at end of file +chromeos-chrome-amd64-broadwell-80-3943.1-1572873357-benchmark-80.0.3961.0-r1-redacted.afdo.xz \ No newline at end of file
diff --git a/chromeos/profiles/silvermont.afdo.newest.txt b/chromeos/profiles/silvermont.afdo.newest.txt index 2b766db..3e19076 100644 --- a/chromeos/profiles/silvermont.afdo.newest.txt +++ b/chromeos/profiles/silvermont.afdo.newest.txt
@@ -1 +1 @@ -chromeos-chrome-amd64-silvermont-80-3943.1-1572866479-benchmark-80.0.3960.0-r1-redacted.afdo.xz \ No newline at end of file +chromeos-chrome-amd64-silvermont-80-3943.1-1572866479-benchmark-80.0.3961.0-r1-redacted.afdo.xz \ No newline at end of file
diff --git a/components/cdm/browser/cdm_message_filter_android.cc b/components/cdm/browser/cdm_message_filter_android.cc index 1357cf68..90136e5 100644 --- a/components/cdm/browser/cdm_message_filter_android.cc +++ b/components/cdm/browser/cdm_message_filter_android.cc
@@ -201,10 +201,10 @@ bool are_overlay_supported = content::AndroidOverlayProvider::GetInstance()->AreOverlaysSupported(); - bool use_android_overlay = - base::FeatureList::IsEnabled(media::kUseAndroidOverlay); + bool overlay_fullscreen_video = + base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo); if (force_to_support_secure_codecs_ || - (are_overlay_supported && use_android_overlay)) { + (are_overlay_supported && overlay_fullscreen_video)) { DVLOG(1) << "Rendering the output of secure codecs is supported!"; response->secure_codecs = GetSupportedCodecs(request, true); }
diff --git a/components/media_message_center/media_notification_item.cc b/components/media_message_center/media_notification_item.cc index cd56d6b..8f3cee72 100644 --- a/components/media_message_center/media_notification_item.cc +++ b/components/media_message_center/media_notification_item.cc
@@ -8,10 +8,10 @@ // static const char MediaNotificationItem::kUserActionHistogramName[] = - "Media.Notification.Source"; + "Media.Notification.UserAction"; // static const char MediaNotificationItem::kSourceHistogramName[] = - "Media.Notification.UserAction"; + "Media.Notification.Source"; } // namespace media_message_center
diff --git a/components/module_installer/readme.md b/components/module_installer/readme.md new file mode 100644 index 0000000..f24916f --- /dev/null +++ b/components/module_installer/readme.md
@@ -0,0 +1,50 @@ +# Chrome on Android Dynamic Feature Module Installer Backend + +This component houses code to install and load Android +[dynamice feature modules](https://developer.android.com/guide/app-bundle). See +the [onboarding guide](../../docs/android_dynamic_feature_modules.md) for how to +create such a feature module in Chrome. Broadly, this component offers two APIs +- _install engine_ to install modules and _module builder_ to set up modules on +first access. + +## Install Engine + +The install engine is a wrapper around Play Core's +[split install API](https://developer.android.com/guide/app-bundle/playcore) +that performs extra setup such as +[SplitCompat](https://developer.android.com/guide/app-bundle/playcore#access_downloaded_modules), +collects metrics and provides +[fake install](android/java/src/org/chromium/components/module_installer/engine/FakeEngine.java). +You can install a module by name with the following code snippet: + +```java +InstallEngine installEngine = new EngineFactory().getEngine(); +installEngine.install("foo", success -> { + // Module installed successfully if |success| is true. +}); +``` + +You can use the install engine on its own but will have to take care of module +setup such as loading native code and resources. To simplify that you can use +the module builder API. + +## Module Builder + +The module builder simplifies module set up by loading native code and resources +on first module access and determines whether a module is installed. The module +builder uses the install engine in the back. It primarily provides the following +building blocks: + +* [`@ModuleInterface`](android/java/src/org/chromium/components/module_installer/builder/ModuleInterface.java) + to annotate the entry point of your module. Using this with the + [`module_interface_processor`](android/BUILD.gn) will create a module class + such as `FooModule` that lets you install and load a module. See + [`Module`](android/java/src/org/chromium/components/module_installer/builder/Module.java) + for its interface. + +* [`Module`](android/java/src/org/chromium/components/module_installer/builder/Module.java) + needs to be able to retrieve a + [`ModuleDescriptor`](android/java/src/org/chromium/components/module_installer/builder/ModuleDescriptor.java) + implementation for each module via reflection. You can create such an + implementation with the [`module_desc_java`](android/module_desc_java.gni) + template.
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc index 72fca90..226d09dc 100644 --- a/components/ntp_snippets/features.cc +++ b/components/ntp_snippets/features.cc
@@ -87,7 +87,7 @@ // Provides ability to customize the referrer URL. // When specifying a referrer through a field trial, it must contain a path. // In case of default value above the path is empty, but it is specified. -base::FeatureParam<std::string> kArticleSuggestionsReferrerURLParam{ +const base::FeatureParam<std::string> kArticleSuggestionsReferrerURLParam{ &kArticleSuggestionsFeature, "referrer_url", kDefaultReferrerUrl}; std::string GetContentSuggestionsReferrerURL() {
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc index a5d9d116..b4ee988 100644 --- a/components/omnibox/browser/omnibox_popup_model.cc +++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -180,16 +180,9 @@ DCHECK(!result().empty()); DCHECK_NE(kNoMatch, selected_line_); - const AutocompleteResult& result = this->result(); - if (result.empty()) - return; - - const AutocompleteMatch& match = result.match_at(selected_line_); + const AutocompleteMatch& match = result().match_at(selected_line_); GURL current_destination(match.destination_url); - - if (state == KEYWORD) { - DCHECK(match.associated_keyword.get()); - } + DCHECK((state != KEYWORD) || match.associated_keyword.get()); if (state == BUTTON_FOCUSED) { // TODO(orinj): If in-suggestion Pedals are kept, refactor a bit @@ -201,10 +194,10 @@ selected_line_state_ = state; view_->InvalidateLine(selected_line_); - // Ensures update of accessibility data for button text. if (state == BUTTON_FOCUSED) { edit_model_->view()->SetAccessibilityLabel(edit_model_->view()->GetText(), match); + view_->ProvideButtonFocusHint(selected_line_); } }
diff --git a/components/omnibox/browser/omnibox_popup_model_unittest.cc b/components/omnibox/browser/omnibox_popup_model_unittest.cc index 5c1ea279..c3e818b 100644 --- a/components/omnibox/browser/omnibox_popup_model_unittest.cc +++ b/components/omnibox/browser/omnibox_popup_model_unittest.cc
@@ -33,6 +33,7 @@ void InvalidateLine(size_t line) override {} void OnLineSelected(size_t line) override {} void UpdatePopupAppearance() override {} + void ProvideButtonFocusHint(size_t line) override {} void OnMatchIconUpdated(size_t match_index) override {} void OnDragCanceled() override {} };
diff --git a/components/omnibox/browser/omnibox_popup_view.h b/components/omnibox/browser/omnibox_popup_view.h index c2cfb4a..e5accd4f 100644 --- a/components/omnibox/browser/omnibox_popup_view.h +++ b/components/omnibox/browser/omnibox_popup_view.h
@@ -32,6 +32,9 @@ // mean opening or closing the window. virtual void UpdatePopupAppearance() = 0; + // Called to inform result view of button focus. + virtual void ProvideButtonFocusHint(size_t line) = 0; + // Notification that the icon used for the given match has been updated. virtual void OnMatchIconUpdated(size_t match_index) = 0;
diff --git a/components/optimization_guide/optimization_guide_constants.cc b/components/optimization_guide/optimization_guide_constants.cc index ee89a1d..3657d2e 100644 --- a/components/optimization_guide/optimization_guide_constants.cc +++ b/components/optimization_guide/optimization_guide_constants.cc
@@ -20,4 +20,6 @@ const char kLoadedHintLocalHistogramString[] = "OptimizationGuide.LoadedHint.Result"; +const char kOptimizationGuideHintStore[] = "previews_hint_cache_store"; + } // namespace optimization_guide
diff --git a/components/optimization_guide/optimization_guide_constants.h b/components/optimization_guide/optimization_guide_constants.h index 9c566dd..33b656b 100644 --- a/components/optimization_guide/optimization_guide_constants.h +++ b/components/optimization_guide/optimization_guide_constants.h
@@ -25,6 +25,9 @@ // the cache and are ready for use. extern const char kLoadedHintLocalHistogramString[]; +// The folder where the hint data will be stored on disk. +extern const char kOptimizationGuideHintStore[]; + } // namespace optimization_guide #endif // COMPONENTS_OPTIMIZATION_GUIDE_OPTIMIZATION_GUIDE_CONSTANTS_H_
diff --git a/components/optimization_guide/optimization_guide_store.cc b/components/optimization_guide/optimization_guide_store.cc index 04343176..bf183c5 100644 --- a/components/optimization_guide/optimization_guide_store.cc +++ b/components/optimization_guide/optimization_guide_store.cc
@@ -27,9 +27,6 @@ static_cast<int>(OptimizationGuideStore::StoreEntryType::kMaxValue), "mismatched StoreEntryType enums"); -// The folder where the data will be stored on disk. -constexpr char kOptimizationGuideStore[] = "previews_hint_cache_store"; - // The amount of data to build up in memory before converting to a sorted on- // disk file. constexpr size_t kDatabaseWriteBufferSizeBytes = 128 * 1024; @@ -97,10 +94,8 @@ leveldb_proto::ProtoDatabaseProvider* database_provider, const base::FilePath& database_dir, scoped_refptr<base::SequencedTaskRunner> store_task_runner) { - base::FilePath hint_store_dir = - database_dir.AppendASCII(kOptimizationGuideStore); database_ = database_provider->GetDB<proto::StoreEntry>( - leveldb_proto::ProtoDbType::HINT_CACHE_STORE, hint_store_dir, + leveldb_proto::ProtoDbType::HINT_CACHE_STORE, database_dir, store_task_runner); RecordStatusChange(status_); @@ -216,7 +211,7 @@ EntryKeyPrefix filter_prefix = GetComponentHintEntryKeyPrefixWithoutVersion(); // Add the new component data and purge any old component hints from the db. - // After processing finishes, OnUpdateHints() is called, which loads + // After processing finishes, OnUpdateStore() is called, which loads // the updated hint entry keys from the database. database_->UpdateEntriesWithRemoveFilter( component_data->TakeUpdateEntries(), @@ -227,7 +222,7 @@ key.compare(0, filter_prefix.length(), filter_prefix) == 0; }, retain_prefix, filter_prefix), - base::BindOnce(&OptimizationGuideStore::OnUpdateHints, + base::BindOnce(&OptimizationGuideStore::OnUpdateStore, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } @@ -256,7 +251,7 @@ fetched_hints_data->TakeUpdateEntries(), base::BindRepeating(&DatabasePrefixFilter, GetMetadataTypeEntryKey(MetadataType::kFetched)), - base::BindOnce(&OptimizationGuideStore::OnUpdateHints, + base::BindOnce(&OptimizationGuideStore::OnUpdateStore, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); } @@ -309,7 +304,7 @@ return keys_to_remove->find(key) != keys_to_remove->end(); }, keys_to_remove.get()), - base::BindOnce(&OptimizationGuideStore::OnUpdateHints, + base::BindOnce(&OptimizationGuideStore::OnUpdateStore, weak_ptr_factory_.GetWeakPtr(), base::DoNothing::Once())); } @@ -531,19 +526,18 @@ // TODO(mcrouse): Add histogram to record the number of hints being removed. entry_keys_.reset(); - // Removes all |kFetchedHint| store entries. OnUpdateHints will handle - // updating status and re-filling hint_entry_keys with the hints still in the + // Removes all |kFetchedHint| store entries. OnUpdateStore will handle + // updating status and re-filling entry_keys with the entries still in the // store. database_->UpdateEntriesWithRemoveFilter( std::move(entries_to_save), // this should be empty. base::BindRepeating(&DatabasePrefixFilter, GetFetchedHintEntryKeyPrefix()), - base::BindOnce(&OptimizationGuideStore::OnUpdateHints, + base::BindOnce(&OptimizationGuideStore::OnUpdateStore, weak_ptr_factory_.GetWeakPtr(), base::DoNothing::Once())); } -void OptimizationGuideStore::MaybeLoadHintEntryKeys( - base::OnceClosure callback) { +void OptimizationGuideStore::MaybeLoadEntryKeys(base::OnceClosure callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // If the database is unavailable or if there's an in-flight component data @@ -559,25 +553,25 @@ // loaded by the DB. Ownership of the KeySet is passed into the // LoadKeysAndEntriesCallback callback, guaranteeing that the KeySet has a // lifespan longer than the filter calls. - std::unique_ptr<EntryKeySet> hint_entry_keys(std::make_unique<EntryKeySet>()); - EntryKeySet* raw_hint_entry_keys_pointer = hint_entry_keys.get(); + std::unique_ptr<EntryKeySet> entry_keys(std::make_unique<EntryKeySet>()); + EntryKeySet* raw_entry_keys_pointer = entry_keys.get(); database_->LoadKeysAndEntriesWithFilter( base::BindRepeating( - [](EntryKeySet* hint_entry_keys, const std::string& filter_prefix, + [](EntryKeySet* entry_keys, const std::string& filter_prefix, const std::string& entry_key) { if (entry_key.compare(0, filter_prefix.length(), filter_prefix) != 0) { - hint_entry_keys->insert(entry_key); + entry_keys->insert(entry_key); } return false; }, - raw_hint_entry_keys_pointer, GetMetadataEntryKeyPrefix()), - base::BindOnce(&OptimizationGuideStore::OnLoadHintEntryKeys, - weak_ptr_factory_.GetWeakPtr(), std::move(hint_entry_keys), + raw_entry_keys_pointer, GetMetadataEntryKeyPrefix()), + base::BindOnce(&OptimizationGuideStore::OnLoadEntryKeys, + weak_ptr_factory_.GetWeakPtr(), std::move(entry_keys), std::move(callback))); } -size_t OptimizationGuideStore::GetHintEntryKeyCount() const { +size_t OptimizationGuideStore::GetEntryKeyCount() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return entry_keys_ ? entry_keys_->size() : 0; } @@ -691,7 +685,7 @@ } UpdateStatus(Status::kAvailable); - MaybeLoadHintEntryKeys(std::move(callback)); + MaybeLoadEntryKeys(std::move(callback)); } void OptimizationGuideStore::OnPurgeDatabase(base::OnceClosure callback, @@ -704,7 +698,7 @@ std::move(callback).Run(); } -void OptimizationGuideStore::OnUpdateHints(base::OnceClosure callback, +void OptimizationGuideStore::OnUpdateStore(base::OnceClosure callback, bool success) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(data_update_in_flight_); @@ -715,10 +709,10 @@ std::move(callback).Run(); return; } - MaybeLoadHintEntryKeys(std::move(callback)); + MaybeLoadEntryKeys(std::move(callback)); } -void OptimizationGuideStore::OnLoadHintEntryKeys( +void OptimizationGuideStore::OnLoadEntryKeys( std::unique_ptr<EntryKeySet> hint_entry_keys, base::OnceClosure callback, bool success, @@ -801,4 +795,97 @@ std::move(callback).Run(entry_key, std::move(loaded_hint)); } +std::unique_ptr<StoreUpdateData> +OptimizationGuideStore::CreateUpdateDataForPredictionModels() const { + // Create and returns a StoreUpdateData object. This object has prediction + // models from the GetModelsResponse moved into and organizes them in a format + // usable by the store. The object will be stored with + // UpdatePredictionModels(). + return StoreUpdateData::CreatePredictionModelStoreUpdateData(); +} + +void OptimizationGuideStore::UpdatePredictionModels( + std::unique_ptr<StoreUpdateData> prediction_models_update_data, + base::OnceClosure callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(prediction_models_update_data); + DCHECK(!data_update_in_flight_); + + if (!IsAvailable()) { + std::move(callback).Run(); + return; + } + + data_update_in_flight_ = true; + + entry_keys_.reset(); + + std::unique_ptr<EntryVector> entry_vectors = + prediction_models_update_data->TakeUpdateEntries(); + + database_->UpdateEntries( + std::move(entry_vectors), std::make_unique<leveldb_proto::KeyVector>(), + base::BindOnce(&OptimizationGuideStore::OnUpdateStore, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +bool OptimizationGuideStore::FindPredictionModelEntryKey( + proto::OptimizationTarget optimization_target, + OptimizationGuideStore::EntryKey* out_prediction_model_entry_key) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!entry_keys_) + return false; + *out_prediction_model_entry_key = + GetPredictionModelEntryKeyPrefix() + + base::NumberToString(static_cast<int>(optimization_target)); + if (entry_keys_->find(*out_prediction_model_entry_key) != entry_keys_->end()) + return true; + return false; +} + +void OptimizationGuideStore::LoadPredictionModel( + const EntryKey& prediction_model_entry_key, + PredictionModelLoadedCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + if (!IsAvailable()) { + std::move(callback).Run(nullptr); + return; + } + + database_->GetEntry( + prediction_model_entry_key, + base::BindOnce(&OptimizationGuideStore::OnLoadPredictionModel, + weak_ptr_factory_.GetWeakPtr(), std::move(callback))); +} + +void OptimizationGuideStore::OnLoadPredictionModel( + PredictionModelLoadedCallback callback, + bool success, + std::unique_ptr<proto::StoreEntry> entry) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + + // If either the request failed, the store was set to unavailable after the + // request was started, or there's an in-flight update, which + // means the entry is about to be invalidated, then the loaded model should + // not be considered valid. Reset the entry so that nothing is returned to + // the requester. + UMA_HISTOGRAM_BOOLEAN("OptimizationGuide.PredictionModelStore.OnLoadCollided", + data_update_in_flight_); + if (!success || !IsAvailable() || data_update_in_flight_) { + entry.reset(); + } + + if (!entry || !entry->has_prediction_model()) { + std::unique_ptr<proto::PredictionModel> loaded_prediction_model(nullptr); + std::move(callback).Run(std::move(loaded_prediction_model)); + return; + } + + std::unique_ptr<proto::PredictionModel> loaded_prediction_model( + entry->release_prediction_model()); + std::move(callback).Run(std::move(loaded_prediction_model)); +} + } // namespace optimization_guide
diff --git a/components/optimization_guide/optimization_guide_store.h b/components/optimization_guide/optimization_guide_store.h index b914a8d..92f701d3 100644 --- a/components/optimization_guide/optimization_guide_store.h +++ b/components/optimization_guide/optimization_guide_store.h
@@ -18,6 +18,7 @@ #include "base/version.h" #include "components/leveldb_proto/public/proto_database.h" #include "components/leveldb_proto/public/proto_database_provider.h" +#include "components/optimization_guide/proto/models.pb.h" #include "components/optimization_guide/store_update_data.h" namespace base { @@ -39,6 +40,8 @@ using HintLoadedCallback = base::OnceCallback<void(const std::string&, std::unique_ptr<proto::Hint>)>; + using PredictionModelLoadedCallback = + base::OnceCallback<void(std::unique_ptr<proto::PredictionModel>)>; using EntryKey = std::string; using StoreEntryProtoDatabase = leveldb_proto::ProtoDatabase<proto::StoreEntry>; @@ -135,7 +138,7 @@ void UpdateFetchedHints(std::unique_ptr<StoreUpdateData> fetched_hints_data, base::OnceClosure callback); - // Removes fetched hint store entries from |this|. |hint_entry_keys_| is + // Removes fetched hint store entries from |this|. |entry_keys_| is // updated after the fetched hint entries are removed. void ClearFetchedHintsFromDatabase(); @@ -158,10 +161,38 @@ base::Time FetchedHintsUpdateTime() const; // Removes all fetched hints that have expired from the store. - // |hint_entry_keys| is updated after the expired fetched hints are + // |entry_keys_| is updated after the expired fetched hints are // removed. void PurgeExpiredFetchedHints(); + // Creates and returns a StoreUpdateData object for Prediction Models. This + // object is used to collect a batch of prediction models in a format that is + // usable to update the store on a background thread. This is always created + // when prediction models have been successfully fetched from the remote + // Optimization Guide Service so the store can update old prediction models. + std::unique_ptr<StoreUpdateData> CreateUpdateDataForPredictionModels() const; + + // Updates the prediciton models contained in the store. The callback is run + // asynchronously after the database stores the prediction models. + void UpdatePredictionModels( + std::unique_ptr<StoreUpdateData> prediction_models_update_data, + base::OnceClosure callback); + + // Finds the entry key for the prediction model if it is known to the store. + // Returns true if an entry key is found and |out_prediction_model_entry_key| + // is populated with the matching key. + bool FindPredictionModelEntryKey( + proto::OptimizationTarget optimization_target, + OptimizationGuideStore::EntryKey* out_prediction_model_entry_key); + + // Loads the prediction model specified by |prediction_model_entry_key|. After + // the load finishes, the prediction model data is passed to |callback|. In + // the case where the prediction model cannot be loaded, the callback is run + // with a nullptr. Depending on the load result, the callback may be + // synchronous or asynchronous. + void LoadPredictionModel(const EntryKey& prediction_model_entry_key, + PredictionModelLoadedCallback callback); + private: friend class OptimizationGuideStoreTest; friend class StoreUpdateData; @@ -237,15 +268,14 @@ // their default state. Called after the database is destroyed. void ClearComponentVersion(); - // Asynchronously loads the hint entry keys from the store, populates - // |hint_entry_keys_| with them, and runs the provided callback after they - // finish loading. In the case where there is currently an in-flight component - // update, this does nothing, as the hint entry keys will be loaded after the - // component update completes. - void MaybeLoadHintEntryKeys(base::OnceClosure callback); + // Asynchronously loads the entry keys from the store, populates |entry_keys_| + // with them, and runs the provided callback after they finish loading. In the + // case where there is currently an in-flight update, this does nothing, as + // the entry keys will be loaded after the update completes. + void MaybeLoadEntryKeys(base::OnceClosure callback); - // Returns the total hint entry keys contained within the store. - size_t GetHintEntryKeyCount() const; + // Returns the total entry keys contained within the store. + size_t GetEntryKeyCount() const; // Finds the most specific host suffix of the host name that the store has an // hint with the provided prefix, |hint_entry_key_prefix|. |out_entry_key| is @@ -283,20 +313,20 @@ // Callback that runs after the database is purged during initialization. void OnPurgeDatabase(base::OnceClosure callback, bool success); - // Callback that runs after the hints data within the store is fully - // updated. If the update was successful, it attempts to load all of the hint + // Callback that runs after the data within the store is fully + // updated. If the update was successful, it attempts to load all of the // entry keys contained within the database. - void OnUpdateHints(base::OnceClosure callback, bool success); + void OnUpdateStore(base::OnceClosure callback, bool success); // Callback that runs after the hint entry keys are fully loaded. If there's // currently an in-flight component update, then the hint entry keys will be // loaded again after the component update completes, so the results are - // tossed; otherwise, |hint_entry_keys| is moved into |hint_entry_keys_|. + // tossed; otherwise, |entry_keys| is moved into |entry_keys_|. // Regardless of the outcome of loading the keys, the callback always runs. - void OnLoadHintEntryKeys(std::unique_ptr<EntryKeySet> hint_entry_keys, - base::OnceClosure callback, - bool success, - std::unique_ptr<EntryMap> unused); + void OnLoadEntryKeys(std::unique_ptr<EntryKeySet> entry_keys, + base::OnceClosure callback, + bool success, + std::unique_ptr<EntryMap> unused); // Callback that runs after a hint entry is loaded from the database. If // there's currently an in-flight component update, then the hint is about to @@ -309,6 +339,17 @@ bool success, std::unique_ptr<proto::StoreEntry> entry); + // Callback that runs after a prediction model entry is loaded from the + // database. If there's currently an in-flight update, then the data could be + // invalidated, so loaded model is discarded. Otherwise, the prediction model + // is released into the callback, allowing the caller to own the prediction + // model without copying it. Regardless of the success or failure of + // retrieving the key, the callback always runs (it simply runs with a nullptr + // on failure). + void OnLoadPredictionModel(PredictionModelLoadedCallback callback, + bool success, + std::unique_ptr<proto::StoreEntry> entry); + // Proto database used by the store. std::unique_ptr<StoreEntryProtoDatabase> database_;
diff --git a/components/optimization_guide/optimization_guide_store_unittest.cc b/components/optimization_guide/optimization_guide_store_unittest.cc index 72c8ea3..6efd1fa 100644 --- a/components/optimization_guide/optimization_guide_store_unittest.cc +++ b/components/optimization_guide/optimization_guide_store_unittest.cc
@@ -15,6 +15,7 @@ #include "components/leveldb_proto/testing/fake_db.h" #include "components/optimization_guide/optimization_guide_features.h" #include "components/optimization_guide/proto/hint_cache.pb.h" +#include "components/optimization_guide/proto/models.pb.h" #include "components/optimization_guide/store_update_data.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -46,6 +47,22 @@ kValid, }; +std::unique_ptr<proto::PredictionModel> CreatePredictionModel() { + std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model = + std::make_unique<optimization_guide::proto::PredictionModel>(); + + optimization_guide::proto::ModelInfo* model_info = + prediction_model->mutable_model_info(); + model_info->set_version(1); + model_info->add_supported_model_features( + proto::CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE); + model_info->set_optimization_target( + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD); + model_info->add_supported_model_types( + proto::ModelType::MODEL_TYPE_DECISION_TREE); + return prediction_model; +} + } // namespace class OptimizationGuideStoreTest : public testing::Test { @@ -137,21 +154,33 @@ } } + // Moves a prediction model with |optimization_target| into the update data. + void SeedPredictionModelUpdateData( + StoreUpdateData* update_data, + optimization_guide::proto::OptimizationTarget optimization_target) { + std::unique_ptr<optimization_guide::proto::PredictionModel> + prediction_model = CreatePredictionModel(); + prediction_model->mutable_model_info()->set_optimization_target( + optimization_target); + update_data->MovePredictionModelIntoUpdateData( + std::move(*prediction_model)); + } + void CreateDatabase() { // Reset everything. db_ = nullptr; - hint_store_.reset(); + guide_store_.reset(); // Setup the fake db and the class under test. auto db = std::make_unique<FakeDB<StoreEntry>>(&db_store_); db_ = db.get(); - hint_store_ = std::make_unique<OptimizationGuideStore>(std::move(db)); + guide_store_ = std::make_unique<OptimizationGuideStore>(std::move(db)); } void InitializeDatabase(bool success, bool purge_existing_data = false) { EXPECT_CALL(*this, OnInitialized()); - hint_store()->Initialize( + guide_store()->Initialize( purge_existing_data, base::BindOnce(&OptimizationGuideStoreTest::OnInitialized, base::Unretained(this))); @@ -173,7 +202,7 @@ // OnLoadMetadata callback db()->LoadCallback(true); if (state == MetadataSchemaState::kValid) { - // OnLoadHintEntryKeys callback + // OnLoadEntryKeys callback db()->LoadCallback(true); } else { // OnPurgeDatabase callback @@ -184,15 +213,15 @@ void UpdateComponentHints(std::unique_ptr<StoreUpdateData> component_data, bool update_success = true, bool load_hint_entry_keys_success = true) { - EXPECT_CALL(*this, OnUpdateHints()); - hint_store()->UpdateComponentHints( + EXPECT_CALL(*this, OnUpdateStore()); + guide_store()->UpdateComponentHints( std::move(component_data), - base::BindOnce(&OptimizationGuideStoreTest::OnUpdateHints, + base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore, base::Unretained(this))); - // OnUpdateHints callback + // OnUpdateStore callback db()->UpdateCallback(update_success); if (update_success) { - // OnLoadHintEntryKeys callback + // OnLoadEntryKeys callback db()->LoadCallback(load_hint_entry_keys_success); } } @@ -200,33 +229,50 @@ void UpdateFetchedHints(std::unique_ptr<StoreUpdateData> fetched_data, bool update_success = true, bool load_hint_entry_keys_success = true) { - EXPECT_CALL(*this, OnUpdateHints()); - hint_store()->UpdateFetchedHints( + EXPECT_CALL(*this, OnUpdateStore()); + guide_store()->UpdateFetchedHints( std::move(fetched_data), - base::BindOnce(&OptimizationGuideStoreTest::OnUpdateHints, + base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore, base::Unretained(this))); - // OnUpdateHints callback + // OnUpdateStore callback db()->UpdateCallback(update_success); if (update_success) { - // OnLoadHintEntryKeys callback + // OnLoadEntryKeys callback db()->LoadCallback(load_hint_entry_keys_success); } } + void UpdatePredictionModels( + std::unique_ptr<StoreUpdateData> prediction_models_data, + bool update_success = true, + bool load_prediction_models_entry_keys_success = true) { + EXPECT_CALL(*this, OnUpdateStore()); + guide_store()->UpdatePredictionModels( + std::move(prediction_models_data), + base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore, + base::Unretained(this))); + // OnUpdateStore callback + db()->UpdateCallback(update_success); + if (update_success) { + // OnLoadEntryKeys callback + db()->LoadCallback(load_prediction_models_entry_keys_success); + } + } + void ClearFetchedHintsFromDatabase() { - hint_store()->ClearFetchedHintsFromDatabase(); + guide_store()->ClearFetchedHintsFromDatabase(); db()->UpdateCallback(true); db()->LoadCallback(true); } void PurgeExpiredFetchedHints() { - hint_store()->PurgeExpiredFetchedHints(); + guide_store()->PurgeExpiredFetchedHints(); // OnFetchedHintsLoadedToMaybePurge db()->LoadCallback(true); - // OnUpdateHints + // OnUpdateStore db()->UpdateCallback(true); - // OnLoadHintEntryKeys callback + // OnLoadEntryKeys callback db()->LoadCallback(true); } @@ -293,11 +339,11 @@ } size_t GetDBStoreEntryCount() const { return db_store_.size(); } - size_t GetStoreHintEntryKeyCount() const { - return hint_store_->GetHintEntryKeyCount(); + size_t GetStoreEntryKeyCount() const { + return guide_store_->GetEntryKeyCount(); } - OptimizationGuideStore* hint_store() { return hint_store_.get(); } + OptimizationGuideStore* guide_store() { return guide_store_.get(); } FakeDB<proto::StoreEntry>* db() { return db_; } const OptimizationGuideStore::EntryKey& last_loaded_hint_entry_key() const { @@ -306,22 +352,32 @@ proto::Hint* last_loaded_hint() { return last_loaded_hint_.get(); } + proto::PredictionModel* last_loaded_prediction_model() { + return last_loaded_prediction_model_.get(); + } + void OnHintLoaded(const OptimizationGuideStore::EntryKey& hint_entry_key, std::unique_ptr<proto::Hint> loaded_hint) { last_loaded_hint_entry_key_ = hint_entry_key; last_loaded_hint_ = std::move(loaded_hint); } + void OnPredictionModelLoaded( + std::unique_ptr<proto::PredictionModel> loaded_prediction_model) { + last_loaded_prediction_model_ = std::move(loaded_prediction_model); + } + MOCK_METHOD0(OnInitialized, void()); - MOCK_METHOD0(OnUpdateHints, void()); + MOCK_METHOD0(OnUpdateStore, void()); private: FakeDB<proto::StoreEntry>* db_; StoreEntryMap db_store_; - std::unique_ptr<OptimizationGuideStore> hint_store_; + std::unique_ptr<OptimizationGuideStore> guide_store_; OptimizationGuideStore::EntryKey last_loaded_hint_entry_key_; std::unique_ptr<proto::Hint> last_loaded_hint_; + std::unique_ptr<proto::PredictionModel> last_loaded_prediction_model_; DISALLOW_COPY_AND_ASSIGN(OptimizationGuideStoreTest); }; @@ -357,7 +413,7 @@ // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectTotalCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", 0); @@ -387,7 +443,7 @@ // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectBucketCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", @@ -421,7 +477,7 @@ // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectBucketCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", @@ -449,7 +505,7 @@ // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectTotalCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", 0); @@ -479,7 +535,7 @@ // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectBucketCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", @@ -512,7 +568,7 @@ // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectBucketCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", @@ -540,12 +596,12 @@ // OnLoadMetadata callback db()->LoadCallback(true); - // OnLoadHintEntryKeys callback + // OnLoadEntryKeys callback db()->LoadCallback(false); // In the case where initialization fails, the store should be fully purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); histogram_tester.ExpectBucketCount( "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", @@ -573,7 +629,7 @@ // The store should contain the schema metadata entry and nothing else. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); @@ -603,7 +659,7 @@ // The store should contain the schema metadata entry and nothing else. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); @@ -633,7 +689,7 @@ // The store should contain the schema metadata entry and nothing else. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); @@ -671,7 +727,7 @@ // The store should contain the schema metadata entry and nothing else, as // the initial component hints are all purged. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); @@ -701,7 +757,7 @@ // The store should contain the schema metadata entry and nothing else. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); @@ -734,7 +790,7 @@ // entry, and all of the initial component hints. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(component_hint_count + 3)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), component_hint_count); + EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); ExpectComponentHintsPresent(kDefaultComponentVersion, component_hint_count); @@ -769,7 +825,7 @@ // entry, and all of the initial component hints. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(component_hint_count + 2)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), component_hint_count); + EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); ExpectComponentHintsPresent(kDefaultComponentVersion, component_hint_count); @@ -810,7 +866,7 @@ // entry, and all of the initial component hints. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(component_hint_count + 2)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), component_hint_count); + EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count); EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent()); @@ -838,7 +894,7 @@ // StoreUpdateData for a component update should only be created if the store // is initialized. - EXPECT_FALSE(hint_store()->MaybeCreateUpdateDataForComponentHints( + EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion))); } @@ -852,7 +908,7 @@ // No StoreUpdateData for a component update should be created when the // component version of the update is older than the store's component // version. - EXPECT_FALSE(hint_store()->MaybeCreateUpdateDataForComponentHints( + EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version("0.0.0"))); } @@ -865,7 +921,7 @@ // No StoreUpdateData should be created when the component version of the // update is the same as the store's component version. - EXPECT_FALSE(hint_store()->MaybeCreateUpdateDataForComponentHints( + EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kDefaultComponentVersion))); } @@ -878,7 +934,7 @@ // StoreUpdateData for a component update should be created when there is no // pre-existing component in the store. - EXPECT_TRUE(hint_store()->MaybeCreateUpdateDataForComponentHints( + EXPECT_TRUE(guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kDefaultComponentVersion))); } @@ -891,7 +947,7 @@ // StoreUpdateData for a component update should be created when the component // version of the update is newer than the store's component version. - EXPECT_TRUE(hint_store()->MaybeCreateUpdateDataForComponentHints( + EXPECT_TRUE(guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion))); } @@ -902,7 +958,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), 5); @@ -911,7 +967,7 @@ // The store should be purged if the component data update fails. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); } TEST_F(OptimizationGuideStoreTest, UpdateComponentHintsGetKeysFails) { @@ -921,7 +977,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), 5); @@ -932,7 +988,7 @@ // The store should be purged if loading the keys after the component update // fails. EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0)); - EXPECT_EQ(GetStoreHintEntryKeyCount(), static_cast<size_t>(0)); + EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0)); } TEST_F(OptimizationGuideStoreTest, UpdateComponentHints) { @@ -944,7 +1000,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), update_hint_count); @@ -954,7 +1010,7 @@ // metadata entry, the component metadata entry, and all of the update's // component hints. EXPECT_EQ(GetDBStoreEntryCount(), update_hint_count + 2); - EXPECT_EQ(GetStoreHintEntryKeyCount(), update_hint_count); + EXPECT_EQ(GetStoreEntryKeyCount(), update_hint_count); ExpectComponentHintsPresent(kUpdateComponentVersion, update_hint_count); } @@ -968,7 +1024,7 @@ InitializeStore(schema_state, true /*=purge_existing_data*/); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), update_hint_count); @@ -978,7 +1034,7 @@ // metadata entry, the component metadata entry, and all of the update's // component hints. EXPECT_EQ(GetDBStoreEntryCount(), update_hint_count + 2); - EXPECT_EQ(GetStoreHintEntryKeyCount(), update_hint_count); + EXPECT_EQ(GetStoreEntryKeyCount(), update_hint_count); ExpectComponentHintsPresent(kUpdateComponentVersion, update_hint_count); } @@ -992,7 +1048,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), update_hint_count); @@ -1000,7 +1056,7 @@ // StoreUpdateData for the component update should not be created for a second // component update with the same version as the first component update. - EXPECT_FALSE(hint_store()->MaybeCreateUpdateDataForComponentHints( + EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion))); } @@ -1016,10 +1072,10 @@ // Create two updates for the same component version with different counts. std::unique_ptr<StoreUpdateData> update_data_1 = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); std::unique_ptr<StoreUpdateData> update_data_2 = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data_1); SeedComponentUpdateData(update_data_1.get(), update_hint_count_1); @@ -1030,16 +1086,16 @@ // first with |update_data_1| and then with |update_data_2|. UpdateComponentHints(std::move(update_data_1)); - EXPECT_CALL(*this, OnUpdateHints()); - hint_store()->UpdateComponentHints( + EXPECT_CALL(*this, OnUpdateStore()); + guide_store()->UpdateComponentHints( std::move(update_data_2), - base::BindOnce(&OptimizationGuideStoreTest::OnUpdateHints, + base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore, base::Unretained(this))); // Verify that the store is populated with the component data from // |update_data_1| and not |update_data_2|. EXPECT_EQ(GetDBStoreEntryCount(), update_hint_count_1 + 2); - EXPECT_EQ(GetStoreHintEntryKeyCount(), update_hint_count_1); + EXPECT_EQ(GetStoreEntryKeyCount(), update_hint_count_1); ExpectComponentHintsPresent(kUpdateComponentVersion, update_hint_count_1); } @@ -1049,7 +1105,7 @@ CreateDatabase(); const OptimizationGuideStore::EntryKey kInvalidEntryKey = "invalid"; - hint_store()->LoadHint( + guide_store()->LoadHint( kInvalidEntryKey, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded, base::Unretained(this))); @@ -1068,7 +1124,7 @@ InitializeStore(schema_state); const OptimizationGuideStore::EntryKey kInvalidEntryKey = "invalid"; - hint_store()->LoadHint( + guide_store()->LoadHint( kInvalidEntryKey, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded, base::Unretained(this))); @@ -1094,12 +1150,12 @@ for (size_t i = 0; i < hint_count; ++i) { std::string host_suffix = GetHostSuffix(i); OptimizationGuideStore::EntryKey hint_entry_key; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; continue; } - hint_store()->LoadHint( + guide_store()->LoadHint( hint_entry_key, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded, base::Unretained(this))); @@ -1126,7 +1182,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), update_hint_count); @@ -1137,12 +1193,12 @@ for (size_t i = 0; i < update_hint_count; ++i) { std::string host_suffix = GetHostSuffix(i); OptimizationGuideStore::EntryKey hint_entry_key; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; continue; } - hint_store()->LoadHint( + guide_store()->LoadHint( hint_entry_key, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded, base::Unretained(this))); @@ -1169,7 +1225,7 @@ OptimizationGuideStore::EntryKey hint_entry_key; // Verify that hint entry keys can't be found when the store is unavailable. - EXPECT_FALSE(hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); + EXPECT_FALSE(guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); } TEST_F(OptimizationGuideStoreTest, FindHintEntryKeyInitialData) { @@ -1185,7 +1241,8 @@ for (size_t i = 0; i < hint_count * 2; ++i) { std::string host_suffix = GetHostSuffix(i); OptimizationGuideStore::EntryKey hint_entry_key; - bool success = hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key); + bool success = + guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key); EXPECT_EQ(success, i < hint_count); } } @@ -1199,7 +1256,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); SeedComponentUpdateData(update_data.get(), update_hint_count); @@ -1211,7 +1268,8 @@ for (size_t i = 0; i < update_hint_count * 2; ++i) { std::string host_suffix = GetHostSuffix(i); OptimizationGuideStore::EntryKey hint_entry_key; - bool success = hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key); + bool success = + guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key); EXPECT_EQ(success, i < update_hint_count); } } @@ -1235,7 +1293,7 @@ InitializeStore(schema_state); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->CreateUpdateDataForFetchedHints( + guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time + optimization_guide::features:: StoredFetchedHintsFreshnessDuration()); ASSERT_TRUE(update_data); @@ -1245,7 +1303,8 @@ for (size_t i = 0; i < update_hint_count; ++i) { std::string host_suffix = GetHostSuffix(i); OptimizationGuideStore::EntryKey hint_entry_key; - bool success = hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key); + bool success = + guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key); EXPECT_EQ(success, i < update_hint_count); } } @@ -1262,7 +1321,7 @@ base::Version version("2.0.0"); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); @@ -1279,7 +1338,7 @@ // Add fetched hints to the store that overlap with the same hosts as the // initial set. - update_data = hint_store()->CreateUpdateDataForFetchedHints( + update_data = guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time + optimization_guide::features::StoredFetchedHintsFreshnessDuration()); @@ -1295,7 +1354,7 @@ // as fetched hints take priority. std::string host_suffix = "host.domain2.org"; OptimizationGuideStore::EntryKey hint_entry_key; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; } @@ -1303,7 +1362,7 @@ host_suffix = "subdomain.domain1.org"; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; } @@ -1321,7 +1380,7 @@ base::Version version("2.0.0"); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); @@ -1338,7 +1397,7 @@ // Add fetched hints to the store that overlap with the same hosts as the // initial set. - update_data = hint_store()->CreateUpdateDataForFetchedHints( + update_data = guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time + base::TimeDelta().FromDays(7)); proto::Hint fetched_hint1; @@ -1356,7 +1415,7 @@ // as fetched hints take priority. std::string host_suffix = "host.domain2.org"; OptimizationGuideStore::EntryKey hint_entry_key; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; } @@ -1364,7 +1423,7 @@ host_suffix = "subdomain.domain1.org"; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; } @@ -1375,16 +1434,16 @@ host_suffix = "domain1.org"; // Component hint should still exist. - EXPECT_TRUE(hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); + EXPECT_TRUE(guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); host_suffix = "domain3.org"; // Fetched hint should not still exist. - EXPECT_FALSE(hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); + EXPECT_FALSE(guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); // Add Components back - newer version. base::Version version3("3.0.0"); std::unique_ptr<StoreUpdateData> update_data2 = - hint_store()->MaybeCreateUpdateDataForComponentHints(version3); + guide_store()->MaybeCreateUpdateDataForComponentHints(version3); ASSERT_TRUE(update_data2); @@ -1396,9 +1455,9 @@ UpdateComponentHints(std::move(update_data2)); host_suffix = "host.domain2.org"; - EXPECT_TRUE(hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); + EXPECT_TRUE(guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)); - update_data = hint_store()->CreateUpdateDataForFetchedHints( + update_data = guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time + optimization_guide::features::StoredFetchedHintsFreshnessDuration()); @@ -1413,7 +1472,7 @@ // initial set. host_suffix = "subdomain.domain1.org"; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; } @@ -1431,7 +1490,7 @@ base::Version version("2.0.0"); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); @@ -1448,7 +1507,7 @@ // Add fetched hints to the store that overlap with the same hosts as the // initial set. - update_data = hint_store()->CreateUpdateDataForFetchedHints( + update_data = guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time + base::TimeDelta().FromDays(7)); proto::Hint fetched_hint1; @@ -1463,7 +1522,7 @@ UpdateFetchedHints(std::move(update_data)); // Add expired fetched hints to the store. - update_data = hint_store()->CreateUpdateDataForFetchedHints( + update_data = guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time - base::TimeDelta().FromDays(7)); proto::Hint fetched_hint3; @@ -1480,10 +1539,10 @@ PurgeExpiredFetchedHints(); OptimizationGuideStore::EntryKey hint_entry_key; - EXPECT_FALSE(hint_store()->FindHintEntryKey("domain4.org", &hint_entry_key)); - EXPECT_FALSE(hint_store()->FindHintEntryKey("domain5.org", &hint_entry_key)); - EXPECT_TRUE(hint_store()->FindHintEntryKey("domain2.org", &hint_entry_key)); - EXPECT_TRUE(hint_store()->FindHintEntryKey("domain3.org", &hint_entry_key)); + EXPECT_FALSE(guide_store()->FindHintEntryKey("domain4.org", &hint_entry_key)); + EXPECT_FALSE(guide_store()->FindHintEntryKey("domain5.org", &hint_entry_key)); + EXPECT_TRUE(guide_store()->FindHintEntryKey("domain2.org", &hint_entry_key)); + EXPECT_TRUE(guide_store()->FindHintEntryKey("domain3.org", &hint_entry_key)); } TEST_F(OptimizationGuideStoreTest, FetchedHintsLoadExpiredHint) { @@ -1497,7 +1556,7 @@ base::Version version("2.0.0"); std::unique_ptr<StoreUpdateData> update_data = - hint_store()->MaybeCreateUpdateDataForComponentHints( + guide_store()->MaybeCreateUpdateDataForComponentHints( base::Version(kUpdateComponentVersion)); ASSERT_TRUE(update_data); @@ -1513,7 +1572,7 @@ UpdateComponentHints(std::move(update_data)); // Add fetched hints to the store that expired. - update_data = hint_store()->CreateUpdateDataForFetchedHints( + update_data = guide_store()->CreateUpdateDataForFetchedHints( update_time, update_time - base::TimeDelta().FromDays(10)); proto::Hint fetched_hint1; @@ -1531,11 +1590,11 @@ // as fetched hints take priority. std::string host_suffix = "host.domain2.org"; OptimizationGuideStore::EntryKey hint_entry_key; - if (!hint_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { + if (!guide_store()->FindHintEntryKey(host_suffix, &hint_entry_key)) { FAIL() << "Hint entry not found for host suffix: " << host_suffix; } EXPECT_EQ(hint_entry_key, "3_domain2.org"); - hint_store()->LoadHint( + guide_store()->LoadHint( hint_entry_key, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded, base::Unretained(this))); @@ -1550,4 +1609,136 @@ 1); } +TEST_F(OptimizationGuideStoreTest, FindPredictionModelEntryKey) { + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + SeedInitialData(schema_state, 0); + CreateDatabase(); + InitializeStore(schema_state); + + std::unique_ptr<StoreUpdateData> update_data = + guide_store()->CreateUpdateDataForPredictionModels(); + ASSERT_TRUE(update_data); + SeedPredictionModelUpdateData(update_data.get(), + proto::OPTIMIZATION_TARGET_UNKNOWN); + SeedPredictionModelUpdateData(update_data.get(), + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD); + UpdatePredictionModels(std::move(update_data)); + + OptimizationGuideStore::EntryKey entry_key; + bool success = guide_store()->FindPredictionModelEntryKey( + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key); + EXPECT_TRUE(success); + EXPECT_EQ(entry_key, "4_1"); +} + +TEST_F(OptimizationGuideStoreTest, + FindEntryKeyMissingForMissingPredictionModel) { + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + SeedInitialData(schema_state, 0); + CreateDatabase(); + InitializeStore(schema_state); + + std::unique_ptr<StoreUpdateData> update_data = + guide_store()->CreateUpdateDataForPredictionModels(); + ASSERT_TRUE(update_data); + SeedPredictionModelUpdateData(update_data.get(), + proto::OPTIMIZATION_TARGET_UNKNOWN); + UpdatePredictionModels(std::move(update_data)); + + OptimizationGuideStore::EntryKey entry_key; + bool success = guide_store()->FindPredictionModelEntryKey( + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key); + EXPECT_FALSE(success); + EXPECT_EQ(entry_key, "4_1"); +} + +TEST_F(OptimizationGuideStoreTest, LoadPredictionModel) { + base::HistogramTester histogram_tester; + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + SeedInitialData(schema_state, 0); + CreateDatabase(); + InitializeStore(schema_state); + + std::unique_ptr<StoreUpdateData> update_data = + guide_store()->CreateUpdateDataForPredictionModels(); + ASSERT_TRUE(update_data); + SeedPredictionModelUpdateData(update_data.get(), + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD); + UpdatePredictionModels(std::move(update_data)); + + OptimizationGuideStore::EntryKey entry_key; + bool success = guide_store()->FindPredictionModelEntryKey( + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key); + EXPECT_TRUE(success); + + guide_store()->LoadPredictionModel( + entry_key, + base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded, + base::Unretained(this))); + // OnPredictionModelLoaded callback + db()->GetCallback(true); + + EXPECT_TRUE(last_loaded_prediction_model()); + + histogram_tester.ExpectBucketCount( + "OptimizationGuide.PredictionModelStore.OnLoadCollided", false, 1); +} + +TEST_F(OptimizationGuideStoreTest, LoadPredictionModelOnUnavailableStore) { + base::HistogramTester histogram_tester; + size_t initial_hint_count = 10; + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + SeedInitialData(schema_state, initial_hint_count); + CreateDatabase(); + InitializeStore(schema_state); + + const OptimizationGuideStore::EntryKey kInvalidEntryKey = "4_2"; + guide_store()->LoadPredictionModel( + kInvalidEntryKey, + base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded, + base::Unretained(this))); + // OnPredictionModelLoaded callback + db()->GetCallback(true); + + // Verify that the OnPredictionModelLoaded callback runs when the store is + // unavailable and that the prediction model was correctly set. + EXPECT_FALSE(last_loaded_prediction_model()); + // The load failed because of an unavailable store, not because of a + // collision. + histogram_tester.ExpectBucketCount( + "OptimizationGuide.PredictionModelStore.OnLoadCollided", false, 1); +} + +TEST_F(OptimizationGuideStoreTest, LoadPredictionModelWithUpdateInFlight) { + base::HistogramTester histogram_tester; + MetadataSchemaState schema_state = MetadataSchemaState::kValid; + SeedInitialData(schema_state, 0); + CreateDatabase(); + InitializeStore(schema_state); + + std::unique_ptr<StoreUpdateData> update_data = + guide_store()->CreateUpdateDataForPredictionModels(); + ASSERT_TRUE(update_data); + SeedPredictionModelUpdateData(update_data.get(), + proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD); + guide_store()->UpdatePredictionModels( + std::move(update_data), + base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore, + base::Unretained(this))); + + const OptimizationGuideStore::EntryKey kEntryKey = "4_1"; + guide_store()->LoadPredictionModel( + kEntryKey, + base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded, + base::Unretained(this))); + + db()->GetCallback(true); + + // Verify that the OnPredictionModelLoaded callback runs when the store is + // unavailable and that the prediction model was correctly set. + EXPECT_FALSE(last_loaded_prediction_model()); + histogram_tester.ExpectBucketCount( + "OptimizationGuide.PredictionModelStore.OnLoadCollided", true, 1); +} + } // namespace optimization_guide
diff --git a/components/page_info_strings.grdp b/components/page_info_strings.grdp index 0a31147..4da37838 100644 --- a/components/page_info_strings.grdp +++ b/components/page_info_strings.grdp
@@ -225,6 +225,9 @@ <message name="IDS_PAGE_INFO_TYPE_ADS" desc="The label used for the ads permission controls in the Page Info popup."> Ads </message> + <message name="IDS_PAGE_INFO_TYPE_PROTECTED_MEDIA_IDENTIFIER" desc="The label used for the protected media identifier permission controls in the Page Info popup."> + Protected content + </message> <message name="IDS_PAGE_INFO_TYPE_AUTOPLAY" desc="The label used for the autoplay permission controls in the Page Info popup."> Autoplay </message>
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc index c5e7ac9..000cccea 100644 --- a/components/password_manager/core/common/password_manager_features.cc +++ b/components/password_manager/core/common/password_manager_features.cc
@@ -88,24 +88,24 @@ base::FEATURE_DISABLED_BY_DEFAULT}; // Field trial identifier for password generation requirements. -const char* kGenerationRequirementsFieldTrial = +const char kGenerationRequirementsFieldTrial[] = "PasswordGenerationRequirements"; // The file version number of password requirements files. If the prefix length // changes, this version number needs to be updated. // Default to 0 in order to get an empty requirements file. -const char* kGenerationRequirementsVersion = "version"; +const char kGenerationRequirementsVersion[] = "version"; // Length of a hash prefix of domain names. This is used to shard domains // across multiple files. // Default to 0 in order to put all domain names into the same shard. -const char* kGenerationRequirementsPrefixLength = "prefix_length"; +const char kGenerationRequirementsPrefixLength[] = "prefix_length"; // Timeout (in milliseconds) for password requirements lookups. As this is a // network request in the background that does not block the UI, the impact of // high values is not strong. // Default to 5000 ms. -const char* kGenerationRequirementsTimeout = "timeout"; +const char kGenerationRequirementsTimeout[] = "timeout"; } // namespace features
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h index 50802fe..03f0f06 100644 --- a/components/password_manager/core/common/password_manager_features.h +++ b/components/password_manager/core/common/password_manager_features.h
@@ -42,10 +42,10 @@ // --force-fieldtrials=PasswordGenerationRequirements/Enabled // --force-fieldtrial-params=PasswordGenerationRequirements.Enabled:\ // version/0/prefix_length/0/timeout/5000 -extern const char* kGenerationRequirementsFieldTrial; -extern const char* kGenerationRequirementsVersion; -extern const char* kGenerationRequirementsPrefixLength; -extern const char* kGenerationRequirementsTimeout; +extern const char kGenerationRequirementsFieldTrial[]; +extern const char kGenerationRequirementsVersion[]; +extern const char kGenerationRequirementsPrefixLength[]; +extern const char kGenerationRequirementsTimeout[]; } // namespace features
diff --git a/components/previews/content/previews_optimization_guide_impl.cc b/components/previews/content/previews_optimization_guide_impl.cc index e2a6534..486e2c3b 100644 --- a/components/previews/content/previews_optimization_guide_impl.cc +++ b/components/previews/content/previews_optimization_guide_impl.cc
@@ -81,7 +81,8 @@ hint_cache_(std::make_unique<optimization_guide::HintCache>( std::make_unique<optimization_guide::OptimizationGuideStore>( database_provider, - profile_path, + profile_path.AddExtensionASCII( + optimization_guide::kOptimizationGuideHintStore), background_task_runner_))), top_host_provider_(top_host_provider), time_clock_(base::DefaultClock::GetInstance()),
diff --git a/components/viz/common/gl_helper.cc b/components/viz/common/gl_helper.cc index 1637b30..cabd57e 100644 --- a/components/viz/common/gl_helper.cc +++ b/components/viz/common/gl_helper.cc
@@ -95,9 +95,9 @@ GLenum GetReadbackFormat() const override; protected: - // Returns true if the planerizer should use the faster, two-pass shaders to - // generate the YUV planar outputs. If false, the source will be scanned three - // times, once for each Y/U/V plane. + // Returns true if the planerizer should use the faster, two-pass shaders + // to generate the YUV planar outputs. If false, the source will be + // scanned three times, once for each Y/U/V plane. bool use_mrt() const { return !v_planerizer_; } // Reallocates the intermediate and plane textures, if needed. @@ -112,9 +112,9 @@ private: // These generate the Y/U/V planes. If MRT is being used, |y_planerizer_| - // generates the Y and interim UV plane, |u_planerizer_| generates the final U - // and V planes, and |v_planerizer_| is unused. If MRT is not being used, each - // of these generates only one of the Y/U/V planes. + // generates the Y and interim UV plane, |u_planerizer_| generates the + // final U and V planes, and |v_planerizer_| is unused. If MRT is not + // being used, each of these generates only one of the Y/U/V planes. const std::unique_ptr<GLHelper::ScalerInterface> y_planerizer_; const std::unique_ptr<GLHelper::ScalerInterface> u_planerizer_; const std::unique_ptr<GLHelper::ScalerInterface> v_planerizer_; @@ -122,8 +122,8 @@ // Intermediate texture, holding the scaler's output. base::Optional<TextureHolder> intermediate_; - // Intermediate texture, holding the UV interim output (if the MRT shader is - // being used). + // Intermediate texture, holding the UV interim output (if the MRT shader + // is being used). base::Optional<ScopedTexture> uv_; DISALLOW_COPY_AND_ASSIGN(I420ConverterImpl); @@ -146,6 +146,7 @@ ~CopyTextureToImpl() { CancelRequests(); } void ReadbackTextureAsync(GLuint texture, + GLenum texture_target, const gfx::Size& dst_size, unsigned char* out, SkColorType color_type, @@ -267,8 +268,8 @@ CopyTextureToImpl* copy_impl_; ReadbackSwizzle swizzle_; - // May be null if no scaling is required. This can be changed between calls - // to ReadbackYUV(). + // May be null if no scaling is required. This can be changed between + // calls to ReadbackYUV(). std::unique_ptr<GLHelper::ScalerInterface> scaler_; // These are the output textures for each Y/U/V plane. @@ -366,6 +367,7 @@ void GLHelper::CopyTextureToImpl::ReadbackTextureAsync( GLuint texture, + GLenum texture_target, const gfx::Size& dst_size, unsigned char* out, SkColorType color_type, @@ -379,9 +381,10 @@ IsBGRAReadbackSupported()) { format = GL_BGRA_EXT; } else { - // Note: It's possible the GL implementation supports other readback types. - // However, as of this writing, no caller of this method will request a - // different |color_type| (i.e., requiring using some other GL format). + // Note: It's possible the GL implementation supports other readback + // types. However, as of this writing, no caller of this method will + // request a different |color_type| (i.e., requiring using some other GL + // format). std::move(callback).Run(false); return; } @@ -389,12 +392,13 @@ ScopedFramebuffer dst_framebuffer(gl_); ScopedFramebufferBinder<GL_FRAMEBUFFER> framebuffer_binder(gl_, dst_framebuffer); - ScopedTextureBinder<GL_TEXTURE_2D> texture_binder(gl_, texture); - gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - texture, 0); + gl_->BindTexture(texture_target, texture); + gl_->FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + texture_target, texture, 0); ReadbackAsync(dst_size, dst_size.width() * kBytesPerPixel, dst_size.width() * kBytesPerPixel, out, format, GL_UNSIGNED_BYTE, kBytesPerPixel, std::move(callback)); + gl_->BindTexture(texture_target, 0); } void GLHelper::CopyTextureToImpl::ReadbackDone(Request* finished_request, @@ -490,13 +494,14 @@ GLHelper::~GLHelper() {} void GLHelper::ReadbackTextureAsync(GLuint texture, + GLenum texture_target, const gfx::Size& dst_size, unsigned char* out, SkColorType color_type, base::OnceCallback<void(bool)> callback) { InitCopyTextToImpl(); - copy_texture_to_impl_->ReadbackTextureAsync(texture, dst_size, out, - color_type, std::move(callback)); + copy_texture_to_impl_->ReadbackTextureAsync( + texture, texture_target, dst_size, out, color_type, std::move(callback)); } void GLHelper::InitCopyTextToImpl() { @@ -744,8 +749,8 @@ I420ConverterImpl::Convert(texture, src_texture_size, gfx::Vector2dF(), scaler_.get(), output_rect, y_, u_, v_); - // Read back planes, one at a time. Keep the video frame alive while doing the - // readback. + // Read back planes, one at a time. Keep the video frame alive while doing + // the readback. const gfx::Rect paste_rect(paste_location, output_rect.size()); const auto SetUpAndBindFramebuffer = [this](GLuint framebuffer, GLuint texture) {
diff --git a/components/viz/common/gl_helper.h b/components/viz/common/gl_helper.h index 4f2e4aeb..8ae29d9 100644 --- a/components/viz/common/gl_helper.h +++ b/components/viz/common/gl_helper.h
@@ -164,6 +164,7 @@ // TODO(crbug.com/870036): DEPRECATED. This will be moved to be closer to its // one caller soon. void ReadbackTextureAsync(GLuint texture, + GLenum texture_target, const gfx::Size& dst_size, unsigned char* out, SkColorType color_type,
diff --git a/components/viz/common/gl_helper_unittest.cc b/components/viz/common/gl_helper_unittest.cc index 31a99741..5895c38 100644 --- a/components/viz/common/gl_helper_unittest.cc +++ b/components/viz/common/gl_helper_unittest.cc
@@ -1009,7 +1009,7 @@ base::RunLoop run_loop; bool success = false; helper_->ReadbackTextureAsync( - src_texture, src_size, pixels, color_type, + src_texture, GL_TEXTURE_2D, src_size, pixels, color_type, base::BindOnce( [](bool* success, base::OnceClosure callback, bool result) { *success = result;
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc index 75d4b91c1..ffae69c 100644 --- a/components/viz/service/display/surface_aggregator.cc +++ b/components/viz/service/display/surface_aggregator.cc
@@ -800,6 +800,18 @@ if (root_render_pass->color_space == output_color_space_) return; + // An extra color conversion pass is only done if the display's color + // space is unsuitable as a working color space. This happens only + // on Windows, where HDR output is required to be in a space with a linear + // (or PQ) transfer function. + // TODO(ccameron,sunnyps): Determine if blending in PQ space is close + // enough to sRGB space as to not require this extra pass. + // Or at least to avoid changing behavior. + if (output_color_space_ != gfx::ColorSpace::CreateSCRGBLinear() && + output_color_space_ != gfx::ColorSpace::CreateHDR10()) { + return; + } + gfx::Rect output_rect = root_render_pass->output_rect; CHECK(root_render_pass->transform_to_root_target == gfx::Transform());
diff --git a/components/zucchini/disassembler_elf.cc b/components/zucchini/disassembler_elf.cc index ff3b085b..2405374 100644 --- a/components/zucchini/disassembler_elf.cc +++ b/components/zucchini/disassembler_elf.cc
@@ -208,8 +208,14 @@ // Skip empty sections. These don't affect |offset_bound|, and don't // contribute to RVA-offset mapping. - if (section->sh_size == 0) + if (section->sh_size == 0) { + // Skipping empty sections is only safe if the |sh_offset| is within the + // image. Fail if this is not true as the input is ill-formed. + if (section->sh_offset >= image_.size()) + return false; + continue; + } // Extract dimensions to 32-bit integers to facilitate conversion. Range of // values was ensured above when checking that the section is bounded.
diff --git a/content/browser/accessibility/accessibility_tree_formatter_base.cc b/content/browser/accessibility/accessibility_tree_formatter_base.cc index 90ac4e5..0340968f 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_base.cc +++ b/content/browser/accessibility/accessibility_tree_formatter_base.cc
@@ -52,8 +52,10 @@ formatter = Create(); base::string16 accessibility_contents_utf16; formatter->SetPropertyFilters(property_filters); - formatter->FormatAccessibilityTree(ax_mgr->GetRoot(), - &accessibility_contents_utf16); + std::unique_ptr<base::DictionaryValue> dict = + static_cast<AccessibilityTreeFormatterBase*>(formatter.get()) + ->BuildAccessibilityTree(ax_mgr->GetRoot()); + formatter->FormatAccessibilityTree(*dict, &accessibility_contents_utf16); return accessibility_contents_utf16; } @@ -95,12 +97,11 @@ return false; } -AccessibilityTreeFormatterBase::AccessibilityTreeFormatterBase() - : show_ids_(false) {} +AccessibilityTreeFormatterBase::AccessibilityTreeFormatterBase() = default; -AccessibilityTreeFormatterBase::~AccessibilityTreeFormatterBase() {} +AccessibilityTreeFormatterBase::~AccessibilityTreeFormatterBase() = default; -void AccessibilityTreeFormatterBase::FormatAccessibilityTree( +void AccessibilityTreeFormatterBase::FormatAccessibilityTreeForTesting( BrowserAccessibility* root, base::string16* contents) { std::unique_ptr<base::DictionaryValue> dict = BuildAccessibilityTree(root);
diff --git a/content/browser/accessibility/accessibility_tree_formatter_base.h b/content/browser/accessibility/accessibility_tree_formatter_base.h index 7b1f6b5..56e7244e 100644 --- a/content/browser/accessibility/accessibility_tree_formatter_base.h +++ b/content/browser/accessibility/accessibility_tree_formatter_base.h
@@ -66,13 +66,14 @@ virtual std::unique_ptr<base::DictionaryValue> BuildAccessibilityTree( BrowserAccessibility* root) = 0; + void FormatAccessibilityTreeForTesting(BrowserAccessibility* root, + base::string16* contents); + // AccessibilityTreeFormatter overrides. void AddDefaultFilters( std::vector<PropertyFilter>* property_filters) override; std::unique_ptr<base::DictionaryValue> FilterAccessibilityTree( const base::DictionaryValue& dict) override; - void FormatAccessibilityTree(BrowserAccessibility* root, - base::string16* contents) override; void FormatAccessibilityTree(const base::DictionaryValue& tree_node, base::string16* contents) override; void SetPropertyFilters( @@ -149,7 +150,7 @@ std::vector<NodeFilter> node_filters_; // Whether or not node ids should be included in the dump. - bool show_ids_; + bool show_ids_ = false; DISALLOW_COPY_AND_ASSIGN(AccessibilityTreeFormatterBase); };
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc index aad8de5..d9cc53c 100644 --- a/content/browser/accessibility/accessibility_win_browsertest.cc +++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -38,6 +38,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/url_constants.h" #include "content/public/test/accessibility_notification_waiter.h" +#include "content/public/test/browser_accessibility.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" #include "content/test/content_browser_test_utils_internal.h" @@ -128,9 +129,9 @@ DISALLOW_COPY_AND_ASSIGN(AccessibilityWinBrowserTest); }; -AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() {} +AccessibilityWinBrowserTest::AccessibilityWinBrowserTest() = default; -AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() {} +AccessibilityWinBrowserTest::~AccessibilityWinBrowserTest() = default; base::string16 AccessibilityWinBrowserTest::PrintAXTree() const { std::unique_ptr<AccessibilityTreeFormatter> formatter( @@ -141,11 +142,8 @@ L"*", AccessibilityTreeFormatter::PropertyFilter::ALLOW)}); base::string16 str; - formatter->FormatAccessibilityTree( - static_cast<WebContentsImpl*>(shell()->web_contents()) - ->GetRootBrowserAccessibilityManager() - ->GetRoot(), - &str); + TestBrowserAccessibility::FormatAccessibilityTree( + formatter.get(), GetRootAccessibilityNode(shell()->web_contents()), &str); return str; }
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.cc b/content/browser/accessibility/dump_accessibility_browsertest_base.cc index d7078fd9..55b6b10 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.cc +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.cc
@@ -31,6 +31,7 @@ #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" #include "content/public/test/accessibility_notification_waiter.h" +#include "content/public/test/browser_accessibility.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" @@ -133,11 +134,9 @@ PropertyFilter(base::ASCIIToUTF16("*"), PropertyFilter::ALLOW)); formatter->SetPropertyFilters(property_filters); formatter->set_show_ids(true); - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); base::string16 ax_tree_dump; - formatter->FormatAccessibilityTree( - web_contents->GetRootBrowserAccessibilityManager()->GetRoot(), + TestBrowserAccessibility::FormatAccessibilityTree( + formatter.get(), GetRootAccessibilityNode(shell()->web_contents()), &ax_tree_dump); return ax_tree_dump; }
diff --git a/content/browser/accessibility/dump_accessibility_browsertest_base.h b/content/browser/accessibility/dump_accessibility_browsertest_base.h index cbea701b..5577b91 100644 --- a/content/browser/accessibility/dump_accessibility_browsertest_base.h +++ b/content/browser/accessibility/dump_accessibility_browsertest_base.h
@@ -5,6 +5,7 @@ #ifndef CONTENT_BROWSER_ACCESSIBILITY_DUMP_ACCESSIBILITY_BROWSERTEST_BASE_H_ #define CONTENT_BROWSER_ACCESSIBILITY_DUMP_ACCESSIBILITY_BROWSERTEST_BASE_H_ +#include <memory> #include <string> #include <vector> @@ -16,6 +17,8 @@ namespace content { +class BrowserAccessibility; + // Base class for an accessibility browsertest that takes an HTML file as // input, loads it into a tab, dumps some accessibility data in text format, // then compares that text to an expectation file in the same directory.
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc index 82be5b9f..50b8c8808 100644 --- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc +++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -23,6 +23,7 @@ #include "content/public/common/content_paths.h" #include "content/public/common/content_switches.h" #include "content/public/test/accessibility_notification_waiter.h" +#include "content/public/test/browser_accessibility.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" #include "ui/accessibility/accessibility_switches.h" @@ -147,10 +148,8 @@ formatter->SetPropertyFilters(property_filters_); formatter->SetNodeFilters(node_filters_); base::string16 actual_contents_utf16; - WebContentsImpl* web_contents = - static_cast<WebContentsImpl*>(shell()->web_contents()); - formatter->FormatAccessibilityTree( - web_contents->GetRootBrowserAccessibilityManager()->GetRoot(), + TestBrowserAccessibility::FormatAccessibilityTree( + formatter.get(), GetRootAccessibilityNode(shell()->web_contents()), &actual_contents_utf16); std::string actual_contents = base::UTF16ToUTF8(actual_contents_utf16); return base::SplitString(actual_contents, "\n", base::KEEP_WHITESPACE, @@ -1064,6 +1063,11 @@ RunAriaTest(FILE_PATH_LITERAL("aria-treegrid.html")); } +IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, + AccessibilityAriaTreeDiscontinuous) { + RunAriaTest(FILE_PATH_LITERAL("aria-tree-discontinuous.html")); +} + IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityAriaUndefined) { RunAriaTest(FILE_PATH_LITERAL("aria-undefined.html")); }
diff --git a/content/browser/browser_process_sub_thread.cc b/content/browser/browser_process_sub_thread.cc index 3c6e699..550b8fc 100644 --- a/content/browser/browser_process_sub_thread.cc +++ b/content/browser/browser_process_sub_thread.cc
@@ -17,7 +17,6 @@ #include "content/browser/utility_process_host.h" #include "content/common/child_process_host_impl.h" #include "content/public/browser/browser_child_process_host_iterator.h" -#include "content/public/browser/browser_thread_delegate.h" #include "content/public/common/process_type.h" #include "net/url_request/url_fetcher.h" #include "net/url_request/url_request.h" @@ -32,20 +31,6 @@ namespace content { -namespace { -BrowserThreadDelegate* g_io_thread_delegate = nullptr; -} // namespace - -// static -void BrowserThread::SetIOThreadDelegate(BrowserThreadDelegate* delegate) { - // |delegate| can only be set/unset while BrowserThread::IO isn't up. - DCHECK(!BrowserThread::IsThreadInitialized(BrowserThread::IO)); - // and it cannot be set twice. - DCHECK(!g_io_thread_delegate || !delegate); - - g_io_thread_delegate = delegate; -} - BrowserProcessSubThread::BrowserProcessSubThread(BrowserThread::ID identifier) : base::Thread(BrowserThreadImpl::GetThreadName(identifier)), identifier_(identifier) { @@ -122,9 +107,6 @@ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) IOThreadCleanUp(); - if (identifier_ == BrowserThread::IO && g_io_thread_delegate) - g_io_thread_delegate->CleanUp(); - notification_service_.reset(); #if defined(OS_WIN) @@ -136,12 +118,6 @@ DCHECK_CALLED_ON_VALID_THREAD(browser_thread_checker_); notification_service_ = std::make_unique<NotificationServiceImpl>(); - - if (identifier_ == BrowserThread::IO && g_io_thread_delegate) { - // Allow blocking calls while initializing the IO thread. - base::ScopedAllowBlocking allow_blocking_for_init; - g_io_thread_delegate->Init(); - } } // Mark following two functions as NOINLINE so the compiler doesn't merge
diff --git a/content/browser/child_process_security_policy_impl.cc b/content/browser/child_process_security_policy_impl.cc index a37639e..08fa62cf 100644 --- a/content/browser/child_process_security_policy_impl.cc +++ b/content/browser/child_process_security_policy_impl.cc
@@ -1306,6 +1306,19 @@ return CanCommitStatus::CAN_COMMIT_ORIGIN_AND_URL; } + // Allow "no access" schemes to commit even though |url_origin| and + // |origin| tuples don't match. We have to allow this because Blink's + // SecurityOrigin::CreateWithReferenceOrigin() and url::Origin::Resolve() + // handle "no access" URLs differently. CreateWithReferenceOrigin() treats + // "no access" like data: URLs and returns an opaque origin with |origin| + // as a precursor. Resolve() returns a non-opaque origin consisting of the + // scheme and host portions of the original URL. + // + // TODO(1020201): Make CreateWithReferenceOrigin() & Resolve() consistent + // with each other and then remove this exception. + if (base::Contains(url::GetNoAccessSchemes(), url.scheme())) + return CanCommitStatus::CAN_COMMIT_ORIGIN_AND_URL; + return CanCommitStatus::CANNOT_COMMIT_ORIGIN; }
diff --git a/content/browser/devtools/devtools_url_loader_interceptor.cc b/content/browser/devtools/devtools_url_loader_interceptor.cc index d7cc1cbb..319246ad 100644 --- a/content/browser/devtools/devtools_url_loader_interceptor.cc +++ b/content/browser/devtools/devtools_url_loader_interceptor.cc
@@ -26,6 +26,7 @@ #include "net/http/http_util.h" #include "net/url_request/redirect_util.h" #include "net/url_request/url_request.h" +#include "services/network/public/cpp/cors/cors.h" #include "services/network/public/cpp/resource_request_body.h" #include "third_party/blink/public/platform/resource_request_blocked_reason.h" @@ -161,6 +162,8 @@ using InterceptionStage = DevToolsURLLoaderInterceptor::InterceptionStage; using protocol::Response; using GlobalRequestId = std::tuple<int32_t, int32_t, int32_t>; +using network::mojom::CredentialsMode; +using network::mojom::FetchResponseType; class BodyReader : public mojo::DataPipeDrainer::Client { public: @@ -355,6 +358,10 @@ bool CanGetResponseBody(std::string* error_reason); bool StartJobAndMaybeNotify(); + void UpdateCORSFlag(); + network::mojom::FetchResponseType CalculateResponseTainting(); + network::ResourceRequest GetResourceRequestForCookies(); + const std::string id_prefix_; const GlobalRequestId global_req_id_; const base::UnguessableToken frame_token_; @@ -390,6 +397,8 @@ bool waiting_for_resolution_; int redirect_count_; + bool tainted_origin_ = false; + bool fetch_cors_flag_ = false; std::string current_id_; std::unique_ptr<BodyReader> body_reader_; @@ -692,6 +701,7 @@ } bool InterceptionJob::StartJobAndMaybeNotify() { + UpdateCORSFlag(); start_ticks_ = base::TimeTicks::Now(); start_time_ = base::Time::Now(); @@ -713,6 +723,42 @@ return true; } +// FIXME(caseq): The logic in the three methods below is borrowed from +// CorsURLLoader as a matter of a quick and mergeable fix for crbug.com/1022173. +// This logic should be unified with CorsURLLoader. +network::mojom::FetchResponseType InterceptionJob::CalculateResponseTainting() { + if (fetch_cors_flag_) + return FetchResponseType::kCors; + if (create_loader_params_->request.mode == + network::mojom::RequestMode::kNoCors && + tainted_origin_) { + return FetchResponseType::kOpaque; + } + return FetchResponseType::kBasic; +} + +network::ResourceRequest InterceptionJob::GetResourceRequestForCookies() { + FetchResponseType response_tainting = + fetch_cors_flag_ ? FetchResponseType::kCors : FetchResponseType::kBasic; + + network::ResourceRequest result = create_loader_params_->request; + result.credentials_mode = + network::cors::CalculateCredentialsFlag( + create_loader_params_->request.credentials_mode, response_tainting) + ? CredentialsMode::kInclude + : CredentialsMode::kOmit; + return result; +} + +void InterceptionJob::UpdateCORSFlag() { + if (fetch_cors_flag_) + return; + + const network::ResourceRequest& request = create_loader_params_->request; + fetch_cors_flag_ = network::cors::ShouldCheckCors( + request.url, request.request_initiator, request.mode); +} + bool InterceptionJob::CanGetResponseBody(std::string* error_reason) { if (!(stage_ & InterceptionStage::RESPONSE)) { *error_reason = @@ -1009,7 +1055,7 @@ void InterceptionJob::ProcessSetCookies(const net::HttpResponseHeaders& headers, base::OnceClosure callback) { - if (!create_loader_params_->request.SavesCookies()) { + if (!GetResourceRequestForCookies().SavesCookies()) { std::move(callback).Run(); return; } @@ -1167,7 +1213,7 @@ void InterceptionJob::FetchCookies( network::mojom::CookieManager::GetCookieListCallback callback) { - if (!create_loader_params_->request.SendsCookies()) { + if (!GetResourceRequestForCookies().SendsCookies()) { std::move(callback).Run({}, {}); return; } @@ -1233,6 +1279,12 @@ network::ResourceRequest* request = &create_loader_params_->request; const net::RedirectInfo& info = *response_metadata_->redirect_info; + const auto current_origin = url::Origin::Create(request->url); + if (request->request_initiator && + (!url::Origin::Create(info.new_url).IsSameOriginWith(current_origin) && + !request->request_initiator->IsSameOriginWith(current_origin))) { + tainted_origin_ = true; + } bool clear_body = false; net::RedirectUtil::UpdateHttpRequest(request->url, request->method, info, @@ -1247,6 +1299,8 @@ request->referrer = GURL(info.new_referrer); response_metadata_.reset(); + UpdateCORSFlag(); + if (interceptor_) { // Pretend that each redirect hop is a new request -- this is for // compatibilty with URLRequestJob-based interception implementation.
diff --git a/content/browser/devtools/protocol/tethering_handler.cc b/content/browser/devtools/protocol/tethering_handler.cc index eab85ac..c0d8c328 100644 --- a/content/browser/devtools/protocol/tethering_handler.cc +++ b/content/browser/devtools/protocol/tethering_handler.cc
@@ -33,7 +33,7 @@ const int kMinTetheringPort = 1024; const int kMaxTetheringPort = 65535; -net::NetworkTrafficAnnotationTag kTrafficAnnotation = +const net::NetworkTrafficAnnotationTag kTrafficAnnotation = net::DefineNetworkTrafficAnnotation("tethering_handler_socket", R"( semantics { sender: "Tethering Handler"
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc index 0a45632..cd93395cc 100644 --- a/content/browser/frame_host/navigation_controller_impl.cc +++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -456,8 +456,26 @@ // static std::unique_ptr<NavigationEntry> NavigationController::CreateNavigationEntry( const GURL& url, - const Referrer& referrer, - const base::Optional<url::Origin>& initiator_origin, + Referrer referrer, + base::Optional<url::Origin> initiator_origin, + ui::PageTransition transition, + bool is_renderer_initiated, + const std::string& extra_headers, + BrowserContext* browser_context, + scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory) { + return NavigationControllerImpl::CreateNavigationEntry( + url, referrer, std::move(initiator_origin), + nullptr /* source_site_instance */, transition, is_renderer_initiated, + extra_headers, browser_context, std::move(blob_url_loader_factory)); +} + +// static +std::unique_ptr<NavigationEntryImpl> +NavigationControllerImpl::CreateNavigationEntry( + const GURL& url, + Referrer referrer, + base::Optional<url::Origin> initiator_origin, + SiteInstance* source_site_instance, ui::PageTransition transition, bool is_renderer_initiated, const std::string& extra_headers, @@ -469,6 +487,12 @@ RewriteUrlForNavigation(url, browser_context, &url_to_load, &virtual_url, &reverse_on_redirect); + // Let the NTP override the navigation params and pretend that this is a + // browser-initiated, bookmark-like navigation. + GetContentClient()->browser()->OverrideNavigationParams( + source_site_instance, &transition, &is_renderer_initiated, &referrer, + &initiator_origin); + auto entry = std::make_unique<NavigationEntryImpl>( nullptr, // The site instance for tabs is sent on navigation // (WebContents::GetSiteInstance). @@ -2231,8 +2255,9 @@ // TODO(creis): Ensure this case can't exist in https://crbug.com/524208. entry = NavigationEntryImpl::FromNavigationEntry(CreateNavigationEntry( GURL(url::kAboutBlankURL), referrer, initiator_origin, - page_transition, is_renderer_initiated, extra_headers, - browser_context_, nullptr /* blob_url_loader_factory */)); + source_site_instance, page_transition, is_renderer_initiated, + extra_headers, browser_context_, + nullptr /* blob_url_loader_factory */)); } entry->AddOrUpdateFrameEntry( node, -1, -1, nullptr, @@ -2242,8 +2267,9 @@ } else { // Main frame case. entry = NavigationEntryImpl::FromNavigationEntry(CreateNavigationEntry( - url, referrer, initiator_origin, page_transition, is_renderer_initiated, - extra_headers, browser_context_, blob_url_loader_factory)); + url, referrer, initiator_origin, source_site_instance, page_transition, + is_renderer_initiated, extra_headers, browser_context_, + blob_url_loader_factory)); entry->root_node()->frame_entry->set_source_site_instance( static_cast<SiteInstanceImpl*>(source_site_instance)); entry->root_node()->frame_entry->set_method(method); @@ -2989,8 +3015,9 @@ // TODO(creis): Ensure this case can't exist in https://crbug.com/524208. entry = NavigationEntryImpl::FromNavigationEntry(CreateNavigationEntry( GURL(url::kAboutBlankURL), params.referrer, params.initiator_origin, - params.transition_type, params.is_renderer_initiated, - extra_headers_crlf, browser_context_, blob_url_loader_factory)); + params.source_site_instance.get(), params.transition_type, + params.is_renderer_initiated, extra_headers_crlf, browser_context_, + blob_url_loader_factory)); } entry->AddOrUpdateFrameEntry( @@ -3002,8 +3029,9 @@ // Otherwise, create a pending entry for the main frame. entry = NavigationEntryImpl::FromNavigationEntry(CreateNavigationEntry( params.url, params.referrer, params.initiator_origin, - params.transition_type, params.is_renderer_initiated, - extra_headers_crlf, browser_context_, blob_url_loader_factory)); + params.source_site_instance.get(), params.transition_type, + params.is_renderer_initiated, extra_headers_crlf, browser_context_, + blob_url_loader_factory)); entry->set_source_site_instance( static_cast<SiteInstanceImpl*>(params.source_site_instance.get())); entry->SetRedirectChain(params.redirect_chain);
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h index 97c5935..00ab09d 100644 --- a/content/browser/frame_host/navigation_controller_impl.h +++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -305,6 +305,19 @@ // requests corresponding to the current pending entry. std::unique_ptr<PendingEntryRef> ReferencePendingEntry(); + // Like NavigationController::CreateNavigationEntry, but takes an extra + // |source_site_instance| argument. + static std::unique_ptr<NavigationEntryImpl> CreateNavigationEntry( + const GURL& url, + Referrer referrer, + base::Optional<url::Origin> initiator_origin, + SiteInstance* source_site_instance, + ui::PageTransition transition, + bool is_renderer_initiated, + const std::string& extra_headers, + BrowserContext* browser_context, + scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory); + private: friend class RestoreHelper;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc index 8546749..b2759ee9 100644 --- a/content/browser/frame_host/navigation_request.cc +++ b/content/browser/frame_host/navigation_request.cc
@@ -898,7 +898,7 @@ commit_navigation_client_(mojo::NullAssociatedRemote()), rfh_restored_from_back_forward_cache_( rfh_restored_from_back_forward_cache) { - DCHECK(browser_initiated || common_params_->initiator_origin.has_value()); + DCHECK(browser_initiated_ || common_params_->initiator_origin.has_value()); DCHECK(!IsRendererDebugURL(common_params_->url)); DCHECK(common_params_->method == "POST" || !common_params_->post_data); TRACE_EVENT_ASYNC_BEGIN2("navigation", "NavigationRequest", this, @@ -957,6 +957,20 @@ DCHECK(!RequiresSourceSiteInstance() || source_site_instance_); } + // Let the NTP override the navigation params and pretend that this is a + // browser-initiated, bookmark-like navigation. + if (!browser_initiated_ && source_site_instance_) { + bool is_renderer_initiated = !browser_initiated_; + Referrer referrer(*common_params_->referrer); + GetContentClient()->browser()->OverrideNavigationParams( + source_site_instance_.get(), &common_params_->transition, + &is_renderer_initiated, &referrer, &common_params_->initiator_origin); + common_params_->referrer = + blink::mojom::Referrer::New(referrer.url, referrer.policy); + browser_initiated_ = !is_renderer_initiated; + commit_params_->is_browser_initiated = browser_initiated_; + } + // Store the old RenderFrameHost id at request creation to be used later. previous_render_frame_host_id_ = GlobalFrameRoutingId( frame_tree_node->current_frame_host()->GetProcess()->GetID(), @@ -1026,11 +1040,11 @@ common_params_->referrer->policy, frame_tree_node); if (begin_params_->is_form_submission) { - if (browser_initiated && !commit_params_->post_content_type.empty()) { + if (browser_initiated_ && !commit_params_->post_content_type.empty()) { // This is a form resubmit, so make sure to set the Content-Type header. headers.SetHeaderIfMissing(net::HttpRequestHeaders::kContentType, commit_params_->post_content_type); - } else if (!browser_initiated) { + } else if (!browser_initiated_) { // Save the Content-Type in case the form is resubmitted. This will get // sent back to the renderer in the CommitNavigation IPC. The renderer // will then send it back with the post body so that we can access it @@ -1241,18 +1255,6 @@ frame_tree_node->current_frame_host()->GetSiteInstance(); site_url_ = GetSiteForCommonParamsURL(); - // Let the NTP override the navigation params and pretend that this is a - // browser-initiated, bookmark-like navigation. - bool is_renderer_initiated = !browser_initiated_; - Referrer referrer(*common_params_->referrer); - GetContentClient()->browser()->OverrideNavigationParams( - starting_site_instance_.get(), &common_params_->transition, - &is_renderer_initiated, &referrer, &common_params_->initiator_origin); - common_params_->referrer = - blink::mojom::Referrer::New(referrer.url, referrer.policy); - browser_initiated_ = !is_renderer_initiated; - commit_params_->is_browser_initiated = browser_initiated_; - // Compute the redirect chain. // TODO(clamy): Try to simplify this and have the redirects be part of // CommonNavigationParams.
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc index a4688d0..e36e4fb 100644 --- a/content/browser/frame_host/navigator_impl.cc +++ b/content/browser/frame_host/navigator_impl.cc
@@ -749,12 +749,20 @@ if (has_transient_entry) return nullptr; + // Since GetNavigationEntryForRendererInitiatedNavigation is called from + // OnBeginNavigation, we can assume that no frame proxies are involved and + // therefore that |current_site_instance| is also the |source_site_instance|. + SiteInstance* current_site_instance = + frame_tree_node->current_frame_host()->GetSiteInstance(); + SiteInstance* source_site_instance = current_site_instance; + std::unique_ptr<NavigationEntryImpl> entry = NavigationEntryImpl::FromNavigationEntry( - NavigationController::CreateNavigationEntry( + NavigationControllerImpl::CreateNavigationEntry( common_params.url, content::Referrer(), - common_params.initiator_origin, ui::PAGE_TRANSITION_LINK, - true /* is_renderer_initiated */, std::string(), + common_params.initiator_origin, source_site_instance, + ui::PAGE_TRANSITION_LINK, true /* is_renderer_initiated */, + std::string() /* extra_headers */, controller_->GetBrowserContext(), nullptr /* blob_url_loader_factory */));
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc index d822691d..6de95bbf 100644 --- a/content/browser/navigation_browsertest.cc +++ b/content/browser/navigation_browsertest.cc
@@ -17,6 +17,7 @@ #include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "components/network_session_configurator/common/network_switches.h" +#include "content/browser/browser_url_handler_impl.h" #include "content/browser/child_process_security_policy_impl.h" #include "content/browser/frame_host/navigation_request.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -55,6 +56,7 @@ #include "content/shell/browser/shell_download_manager_delegate.h" #include "content/test/content_browser_test_utils_internal.h" #include "content/test/did_commit_navigation_interceptor.h" +#include "content/test/fake_network_url_loader_factory.h" #include "ipc/ipc_security_test_util.h" #include "mojo/public/cpp/bindings/pending_associated_remote.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -3045,6 +3047,112 @@ EXPECT_EQ(0u, response_2.http_request()->headers.count("Cookie")); } +// Tests for validating URL rewriting behavior like chrome://history to +// chrome-native://history. +class NavigationUrlRewriteBrowserTest : public NavigationBaseBrowserTest { + protected: + static constexpr const char* kRewriteURL = "http://a.com/rewrite"; + static constexpr const char* kNoAccessScheme = "no-access"; + static constexpr const char* kNoAccessURL = "no-access://testing/"; + + class BrowserClient : public ContentBrowserClient { + public: + void BrowserURLHandlerCreated(BrowserURLHandler* handler) override { + handler->AddHandlerPair(RewriteUrl, + BrowserURLHandlerImpl::null_handler()); + } + + void RegisterNonNetworkNavigationURLLoaderFactories( + int frame_tree_node_id, + NonNetworkURLLoaderFactoryMap* factories) override { + auto url_loader_factory = std::make_unique<FakeNetworkURLLoaderFactory>( + "HTTP/1.1 200 OK\nContent-Type: text/html\n\n", "This is a test", + /* network_accessed */ true, net::OK); + factories->emplace(std::string(kNoAccessScheme), + std::move(url_loader_factory)); + } + + bool ShouldAssignSiteForURL(const GURL& url) override { + return !url.SchemeIs(kNoAccessScheme); + } + + static bool RewriteUrl(GURL* url, BrowserContext* browser_context) { + if (*url == GURL(kRewriteURL)) { + *url = GURL(kNoAccessURL); + return true; + } + return false; + } + }; + + void SetUp() override { + url::AddStandardScheme(kNoAccessScheme, url::SCHEME_WITH_HOST); + url::AddNoAccessScheme(kNoAccessScheme); + + NavigationBaseBrowserTest::SetUp(); + } + + void SetUpOnMainThread() override { + NavigationBaseBrowserTest::SetUpOnMainThread(); + ASSERT_TRUE(embedded_test_server()->Start()); + + browser_client_ = std::make_unique<BrowserClient>(); + old_browser_client_ = SetBrowserClientForTesting(browser_client_.get()); + } + + void TearDownOnMainThread() override { + SetBrowserClientForTesting(old_browser_client_); + old_browser_client_ = nullptr; + browser_client_.reset(); + + NavigationBaseBrowserTest::TearDownOnMainThread(); + } + + GURL GetRewriteToNoAccessURL() const { return GURL(kRewriteURL); } + + private: + std::unique_ptr<BrowserClient> browser_client_; + ContentBrowserClient* old_browser_client_; +}; + +INSTANTIATE_TEST_SUITE_P(/* no prefix */, + NavigationUrlRewriteBrowserTest, + ::testing::Bool()); + +// Tests navigating to a URL that gets rewritten to a "no access" URL. This +// mimics the behavior of navigating to special URLs like chrome://newtab and +// chrome://history which get rewritten to "no access" chrome-native:// URLs. +IN_PROC_BROWSER_TEST_P(NavigationUrlRewriteBrowserTest, RewriteToNoAccess) { + // Perform an initial navigation. + { + TestNavigationObserver observer(shell()->web_contents()); + GURL url = embedded_test_server()->GetURL("a.com", "/title1.html"); + EXPECT_TRUE(NavigateToURL(shell(), url)); + EXPECT_EQ(url, observer.last_navigation_url()); + EXPECT_TRUE(observer.last_navigation_succeeded()); + EXPECT_FALSE(observer.last_initiator_origin().has_value()); + } + + // Navigate to the URL that will get rewritten to a "no access" URL. + { + auto* web_contents = shell()->web_contents(); + TestNavigationObserver observer(web_contents); + + // Note: We are using LoadURLParams here because we need to have the + // initiator_origin set and NavigateToURL() does not do that. + NavigationController::LoadURLParams params(GetRewriteToNoAccessURL()); + params.initiator_origin = + web_contents->GetMainFrame()->GetLastCommittedOrigin(); + web_contents->GetController().LoadURLWithParams(params); + web_contents->Focus(); + observer.Wait(); + + EXPECT_EQ(GURL(kNoAccessURL), observer.last_navigation_url()); + EXPECT_TRUE(observer.last_navigation_succeeded()); + EXPECT_TRUE(observer.last_initiator_origin().has_value()); + } +} + // Update the fragment part of the URL while it is currently displaying an error // page. Regression test https://crbug.com/1018385 IN_PROC_BROWSER_TEST_P(NavigationBrowserTest,
diff --git a/content/browser/renderer_host/input/fling_controller.h b/content/browser/renderer_host/input/fling_controller.h index a3d7646..c524d559 100644 --- a/content/browser/renderer_host/input/fling_controller.h +++ b/content/browser/renderer_host/input/fling_controller.h
@@ -30,6 +30,9 @@ virtual void SendGeneratedGestureScrollEvents( const GestureEventWithLatencyInfo& gesture_event) = 0; + + // Returns the size of visible viewport in screen space, in DIPs. + virtual gfx::Size GetRootWidgetViewportSize() = 0; }; // Interface with which the fling progress gets scheduled.
diff --git a/content/browser/renderer_host/input/fling_controller_unittest.cc b/content/browser/renderer_host/input/fling_controller_unittest.cc index aae4bca..ef3b524 100644 --- a/content/browser/renderer_host/input/fling_controller_unittest.cc +++ b/content/browser/renderer_host/input/fling_controller_unittest.cc
@@ -67,6 +67,10 @@ last_sent_gesture_ = gesture_event.event; } + gfx::Size GetRootWidgetViewportSize() override { + return gfx::Size(1920, 1080); + } + // FlingControllerSchedulerClient void ScheduleFlingProgress( base::WeakPtr<FlingController> fling_controller) override {
diff --git a/content/browser/renderer_host/input/fling_scheduler_unittest.cc b/content/browser/renderer_host/input/fling_scheduler_unittest.cc index 549b021..b5715c1c 100644 --- a/content/browser/renderer_host/input/fling_scheduler_unittest.cc +++ b/content/browser/renderer_host/input/fling_scheduler_unittest.cc
@@ -105,6 +105,9 @@ const MouseWheelEventWithLatencyInfo& wheel_event) override {} void SendGeneratedGestureScrollEvents( const GestureEventWithLatencyInfo& gesture_event) override {} + gfx::Size GetRootWidgetViewportSize() override { + return gfx::Size(1920, 1080); + } std::unique_ptr<FlingController> fling_controller_; std::unique_ptr<FakeFlingScheduler> fling_scheduler_;
diff --git a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc index ebad9f6..eb144d60 100644 --- a/content/browser/renderer_host/input/gesture_event_queue_unittest.cc +++ b/content/browser/renderer_host/input/gesture_event_queue_unittest.cc
@@ -94,6 +94,9 @@ const MouseWheelEventWithLatencyInfo& wheel_event) override {} void SendGeneratedGestureScrollEvents( const GestureEventWithLatencyInfo& gesture_event) override {} + gfx::Size GetRootWidgetViewportSize() override { + return gfx::Size(1920, 1080); + } // FlingControllerSchedulerClient void ScheduleFlingProgress(
diff --git a/content/browser/renderer_host/input/input_router_client.h b/content/browser/renderer_host/input/input_router_client.h index 2bd8ae5..e1ee03e 100644 --- a/content/browser/renderer_host/input/input_router_client.h +++ b/content/browser/renderer_host/input/input_router_client.h
@@ -83,6 +83,9 @@ bool up, bool down) = 0; virtual void FallbackCursorModeSetCursorVisibility(bool visible) = 0; + + // Returns the size of visible viewport in screen space, in DIPs. + virtual gfx::Size GetRootWidgetViewportSize() = 0; }; } // namespace content
diff --git a/content/browser/renderer_host/input/input_router_impl.cc b/content/browser/renderer_host/input/input_router_impl.cc index e9615f0..4c23c997a 100644 --- a/content/browser/renderer_host/input/input_router_impl.cc +++ b/content/browser/renderer_host/input/input_router_impl.cc
@@ -458,6 +458,10 @@ gesture_event.latency); } +gfx::Size InputRouterImpl::GetRootWidgetViewportSize() { + return client_->GetRootWidgetViewportSize(); +} + void InputRouterImpl::SendMouseWheelEventImmediately( const MouseWheelEventWithLatencyInfo& wheel_event) { mojom::WidgetInputHandler::DispatchEventCallback callback = base::BindOnce(
diff --git a/content/browser/renderer_host/input/input_router_impl.h b/content/browser/renderer_host/input/input_router_impl.h index d9f4da8b..1ad7df6b 100644 --- a/content/browser/renderer_host/input/input_router_impl.h +++ b/content/browser/renderer_host/input/input_router_impl.h
@@ -156,6 +156,7 @@ const MouseWheelEventWithLatencyInfo& wheel_event) override; void SendGeneratedGestureScrollEvents( const GestureEventWithLatencyInfo& gesture_event) override; + gfx::Size GetRootWidgetViewportSize() override; // MouseWheelEventQueueClient void SendMouseWheelEventImmediately(
diff --git a/content/browser/renderer_host/input/input_router_impl_unittest.cc b/content/browser/renderer_host/input/input_router_impl_unittest.cc index 2145050..6c236e3c 100644 --- a/content/browser/renderer_host/input/input_router_impl_unittest.cc +++ b/content/browser/renderer_host/input/input_router_impl_unittest.cc
@@ -114,6 +114,10 @@ void FallbackCursorModeSetCursorVisibility(bool visible) override {} + gfx::Size GetRootWidgetViewportSize() override { + return gfx::Size(1920, 1080); + } + MockWidgetInputHandler::MessageVector GetAndResetDispatchedMessages() { return widget_input_handler_.GetAndResetDispatchedMessages(); }
diff --git a/content/browser/renderer_host/input/mock_input_router_client.cc b/content/browser/renderer_host/input/mock_input_router_client.cc index 91f9cef2..d153e4a 100644 --- a/content/browser/renderer_host/input/mock_input_router_client.cc +++ b/content/browser/renderer_host/input/mock_input_router_client.cc
@@ -90,6 +90,10 @@ return false; } +gfx::Size MockInputRouterClient::GetRootWidgetViewportSize() { + return gfx::Size(1920, 1080); +} + bool MockInputRouterClient::GetAndResetFilterEventCalled() { bool filter_input_event_called = filter_input_event_called_; filter_input_event_called_ = false;
diff --git a/content/browser/renderer_host/input/mock_input_router_client.h b/content/browser/renderer_host/input/mock_input_router_client.h index fda1e1f..360706e 100644 --- a/content/browser/renderer_host/input/mock_input_router_client.h +++ b/content/browser/renderer_host/input/mock_input_router_client.h
@@ -47,6 +47,7 @@ bool up, bool down) override {} void FallbackCursorModeSetCursorVisibility(bool visible) override {} + gfx::Size GetRootWidgetViewportSize() override; bool GetAndResetFilterEventCalled(); ui::DidOverscrollParams GetAndResetOverscroll();
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index c988820..2a9053a 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -3353,4 +3353,9 @@ transformed_rect_to_zoom)); } +gfx::Size RenderWidgetHostImpl::GetRootWidgetViewportSize() { + auto* root_view = view_->GetRootView(); + return root_view->GetVisibleViewportSize(); +} + } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h index 85ae36e..c428f84 100644 --- a/content/browser/renderer_host/render_widget_host_impl.h +++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -727,6 +727,7 @@ bool up, bool down) override; void FallbackCursorModeSetCursorVisibility(bool visible) override; + gfx::Size GetRootWidgetViewportSize() override; // FrameTokenMessageQueue::Client: void OnInvalidFrameToken(uint32_t frame_token) override;
diff --git a/content/browser/ssl/ssl_error_handler.cc b/content/browser/ssl/ssl_error_handler.cc index ee32e913..de1a214 100644 --- a/content/browser/ssl/ssl_error_handler.cc +++ b/content/browser/ssl/ssl_error_handler.cc
@@ -4,8 +4,6 @@ #include "content/browser/ssl/ssl_error_handler.h" -#include "base/bind.h" -#include "base/task/post_task.h" #include "content/browser/frame_host/navigation_controller_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" @@ -19,37 +17,14 @@ namespace content { -namespace { - -void CompleteCancelRequest( - const base::WeakPtr<SSLErrorHandler::Delegate>& delegate, - const net::SSLInfo& ssl_info, - int error) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (delegate.get()) - delegate->CancelSSLRequest(error, &ssl_info); -} - -void CompleteContinueRequest( - const base::WeakPtr<SSLErrorHandler::Delegate>& delegate) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - if (delegate.get()) { - delegate->ContinueSSLRequest(); - } -} - -} // namespace - SSLErrorHandler::SSLErrorHandler(WebContents* web_contents, const base::WeakPtr<Delegate>& delegate, - BrowserThread::ID delegate_thread, bool is_main_frame_request, const GURL& url, int net_error, const net::SSLInfo& ssl_info, bool fatal) : delegate_(delegate), - delegate_thread_(delegate_thread), request_url_(url), is_main_frame_request_(is_main_frame_request), ssl_info_(ssl_info), @@ -57,45 +32,26 @@ fatal_(fatal), web_contents_(web_contents) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - DCHECK(delegate_thread == BrowserThread::UI || - delegate_thread == BrowserThread::IO); } SSLErrorHandler::~SSLErrorHandler() {} void SSLErrorHandler::CancelRequest() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (delegate_thread_ == BrowserThread::UI) { - if (delegate_) - delegate_->CancelSSLRequest(net::ERR_ABORTED, &ssl_info()); - return; - } - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&CompleteCancelRequest, delegate_, ssl_info(), - net::ERR_ABORTED)); + if (delegate_) + delegate_->CancelSSLRequest(net::ERR_ABORTED, &ssl_info()); } void SSLErrorHandler::DenyRequest() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (delegate_thread_ == BrowserThread::UI) { - if (delegate_) - delegate_->CancelSSLRequest(cert_error_, &ssl_info()); - return; - } - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&CompleteCancelRequest, delegate_, ssl_info(), - cert_error_)); + if (delegate_) + delegate_->CancelSSLRequest(cert_error_, &ssl_info()); } void SSLErrorHandler::ContinueRequest() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (delegate_thread_ == BrowserThread::UI) { - if (delegate_) - delegate_->ContinueSSLRequest(); - return; - } - base::PostTask(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&CompleteContinueRequest, delegate_)); + if (delegate_) + delegate_->ContinueSSLRequest(); } } // namespace content
diff --git a/content/browser/ssl/ssl_error_handler.h b/content/browser/ssl/ssl_error_handler.h index d80dd098..7257e4a 100644 --- a/content/browser/ssl/ssl_error_handler.h +++ b/content/browser/ssl/ssl_error_handler.h
@@ -31,8 +31,6 @@ // call exactly one of those methods exactly once. class SSLErrorHandler { public: - // SSLErrorHandler's delegate lives on the UI or IO thread based on the passed - // in |delegate_thread|. The methods will be called on that thread. class CONTENT_EXPORT Delegate { public: // Called when SSLErrorHandler decides to cancel the request because of @@ -49,7 +47,6 @@ SSLErrorHandler(WebContents* web_contents, const base::WeakPtr<Delegate>& delegate, - BrowserThread::ID delegate_thread, bool is_main_frame_request, const GURL& url, int net_error, @@ -85,12 +82,8 @@ void DenyRequest(); private: - // This is called on |delegate_thread_|. base::WeakPtr<Delegate> delegate_; - // The thread that the delegate is called on. - BrowserThread::ID delegate_thread_; - // The URL for the request that generated the error. const GURL request_url_;
diff --git a/content/browser/ssl/ssl_manager.cc b/content/browser/ssl/ssl_manager.cc index 93cda186..cbf5e4d2 100644 --- a/content/browser/ssl/ssl_manager.cc +++ b/content/browser/ssl/ssl_manager.cc
@@ -103,36 +103,6 @@ DISALLOW_COPY_AND_ASSIGN(SSLManagerSet); }; -void HandleSSLErrorOnUI( - const base::Callback<WebContents*(void)>& web_contents_getter, - const base::WeakPtr<SSLErrorHandler::Delegate>& delegate, - BrowserThread::ID delegate_thread, - bool is_main_frame_request, - const GURL& url, - int net_error, - const net::SSLInfo& ssl_info, - bool fatal) { - content::WebContents* web_contents = web_contents_getter.Run(); - std::unique_ptr<SSLErrorHandler> handler(new SSLErrorHandler( - web_contents, delegate, delegate_thread, is_main_frame_request, url, - net_error, ssl_info, fatal)); - - if (!web_contents) { - // Requests can fail to dispatch because they don't have a WebContents. See - // https://crbug.com/86537. In this case we have to make a decision in this - // function. - handler->CancelRequest(); - return; - } - - NavigationControllerImpl* controller = - static_cast<NavigationControllerImpl*>(&web_contents->GetController()); - controller->SetPendingNavigationSSLError(true); - - SSLManager* manager = controller->ssl_manager(); - manager->OnCertError(std::move(handler)); -} - void LogMixedContentMetrics(MixedContentType type, ukm::SourceId source_id, ukm::UkmRecorder* recorder) { @@ -157,20 +127,27 @@ DVLOG(1) << "OnSSLCertificateError() cert_error: " << net_error << " url: " << url.spec() << " cert_status: " << std::hex << ssl_info.cert_status; + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { - HandleSSLErrorOnUI(web_contents_getter, delegate, BrowserThread::UI, - is_main_frame_request, url, net_error, ssl_info, fatal); + content::WebContents* web_contents = web_contents_getter.Run(); + std::unique_ptr<SSLErrorHandler> handler( + new SSLErrorHandler(web_contents, delegate, is_main_frame_request, url, + net_error, ssl_info, fatal)); + + if (!web_contents) { + // Requests can fail to dispatch because they don't have a WebContents. See + // https://crbug.com/86537. In this case we have to make a decision in this + // function. + handler->CancelRequest(); return; } - // TODO(jam): remove the logic to call this from IO thread once the - // network service code path is the only one. - base::PostTask( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&HandleSSLErrorOnUI, web_contents_getter, delegate, - BrowserThread::IO, is_main_frame_request, url, net_error, - ssl_info, fatal)); + NavigationControllerImpl* controller = + static_cast<NavigationControllerImpl*>(&web_contents->GetController()); + controller->SetPendingNavigationSSLError(true); + + SSLManager* manager = controller->ssl_manager(); + manager->OnCertError(std::move(handler)); } // static
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java index 63b562e..57b37220f2 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
@@ -13,8 +13,8 @@ import org.junit.runner.RunWith; import org.chromium.base.test.BaseJUnit4ClassRunner; +import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.RetryOnFailure; import org.chromium.base.test.util.UrlUtils; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsObserver; @@ -92,7 +92,7 @@ @Test @LargeTest @Feature({"Navigation"}) - @RetryOnFailure + @DisabledTest(message = "crbug.com/1022324") public void testCloseInterstitial() throws ExecutionException { final String proceedCommand = "PROCEED"; final String htmlContent = "<html>"
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn index c4f537c..5dcf1099 100644 --- a/content/public/browser/BUILD.gn +++ b/content/public/browser/BUILD.gn
@@ -99,7 +99,6 @@ "browser_task_traits.h", "browser_thread.cc", "browser_thread.h", - "browser_thread_delegate.h", "browser_url_handler.h", "browsing_data_filter_builder.h", "browsing_data_remover.h",
diff --git a/content/public/browser/accessibility_tree_formatter.h b/content/public/browser/accessibility_tree_formatter.h index 55c3c9f2..21077c5 100644 --- a/content/public/browser/accessibility_tree_formatter.h +++ b/content/public/browser/accessibility_tree_formatter.h
@@ -27,8 +27,6 @@ namespace content { -class BrowserAccessibility; - class AccessibilityTestExpectationsLocator { public: // Suffix of the expectation file corresponding to html file. @@ -127,9 +125,6 @@ virtual std::unique_ptr<base::DictionaryValue> FilterAccessibilityTree( const base::DictionaryValue& dict) = 0; - // Dumps a BrowserAccessibility tree into a string. - virtual void FormatAccessibilityTree(BrowserAccessibility* root, - base::string16* contents) = 0; virtual void FormatAccessibilityTree(const base::DictionaryValue& tree_node, base::string16* contents) = 0;
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h index dcec2a0..af24784 100644 --- a/content/public/browser/browser_thread.h +++ b/content/public/browser/browser_thread.h
@@ -21,7 +21,6 @@ namespace content { -class BrowserThreadDelegate; class BrowserThreadImpl; // Use DCHECK_CURRENTLY_ON(BrowserThread::ID) to assert that a function can only @@ -121,16 +120,6 @@ // sets identifier to its ID. Otherwise returns false. static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT; - // Sets the delegate for BrowserThread::IO. - // - // Only one delegate may be registered at a time. The delegate may be - // unregistered by providing a nullptr pointer. - // - // The delegate can only be registered through this call before - // BrowserThreadImpl(BrowserThread::IO) is created and unregistered after - // it was destroyed and its underlying thread shutdown. - static void SetIOThreadDelegate(BrowserThreadDelegate* delegate); - // Use these templates in conjunction with RefCountedThreadSafe or scoped_ptr // when you want to ensure that an object is deleted on a specific thread. // This is needed when an object can hop between threads (i.e. UI -> IO ->
diff --git a/content/public/browser/browser_thread_delegate.h b/content/public/browser/browser_thread_delegate.h deleted file mode 100644 index 3eb823c..0000000 --- a/content/public/browser/browser_thread_delegate.h +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_DELEGATE_H_ -#define CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_DELEGATE_H_ - -#include "content/common/content_export.h" - -namespace content { - -// A Delegate for content embedders to perform extra initialization/cleanup on -// BrowserThread::IO. -class BrowserThreadDelegate { - public: - virtual ~BrowserThreadDelegate() = default; - - // Called prior to completing initialization of BrowserThread::IO. - virtual void Init() = 0; - - // Called during teardown of BrowserThread::IO. - virtual void CleanUp() = 0; -}; - -} // namespace content - -#endif // CONTENT_PUBLIC_BROWSER_BROWSER_THREAD_DELEGATE_H_
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h index db6a06f..7fa0063 100644 --- a/content/public/browser/navigation_controller.h +++ b/content/public/browser/navigation_controller.h
@@ -105,8 +105,8 @@ // Extra headers are separated by \n. CONTENT_EXPORT static std::unique_ptr<NavigationEntry> CreateNavigationEntry( const GURL& url, - const Referrer& referrer, - const base::Optional<url::Origin>& initiator_origin, + Referrer referrer, + base::Optional<url::Origin> initiator_origin, ui::PageTransition transition, bool is_renderer_initiated, const std::string& extra_headers,
diff --git a/content/public/browser/url_data_source.cc b/content/public/browser/url_data_source.cc index 0cc65ec..9ca008d 100644 --- a/content/public/browser/url_data_source.cc +++ b/content/public/browser/url_data_source.cc
@@ -127,10 +127,6 @@ return std::string(); } -bool URLDataSource::IsGzipped(const std::string& path) { - return false; -} - void URLDataSource::DisablePolymer2ForHost(const std::string& host) {} bool URLDataSource::ShouldReplaceI18nInJS() {
diff --git a/content/public/browser/url_data_source.h b/content/public/browser/url_data_source.h index ed64db6..9e9d150 100644 --- a/content/public/browser/url_data_source.h +++ b/content/public/browser/url_data_source.h
@@ -165,9 +165,6 @@ virtual std::string GetAccessControlAllowOriginForOrigin( const std::string& origin); - // Whether |path| is gzipped (and should be transmitted gzipped). - virtual bool IsGzipped(const std::string& path); - // Called on the UI thread. For the shared resource, disables using Polymer 2 // for requests from |host|, even if WebUIPolymer2 is enabled. Assumes this // method is only called from one host.
diff --git a/content/public/test/browser_accessibility.h b/content/public/test/browser_accessibility.h new file mode 100644 index 0000000..5a85afe --- /dev/null +++ b/content/public/test/browser_accessibility.h
@@ -0,0 +1,29 @@ +// 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. + +#ifndef CONTENT_PUBLIC_TEST_BROWSER_ACCESSIBILITY_H_ +#define CONTENT_PUBLIC_TEST_BROWSER_ACCESSIBILITY_H_ + +#include "ui/accessibility/platform/ax_platform_node_delegate.h" + +namespace content { + +class AccessibilityTreeFormatter; + +// A class that exposes BrowserAccessibility for testing in a controlled manner. +// Additional methods can be added to expose methods from BrowserAccessibility, +// as long as the methods do not expose non-public content/ classes. +class TestBrowserAccessibility : public ui::AXPlatformNodeDelegate { + public: + // Dumps a BrowserAccessibility tree into a string. + static void FormatAccessibilityTree(AccessibilityTreeFormatter* formatter, + TestBrowserAccessibility* root, + base::string16* contents); + + ~TestBrowserAccessibility() override; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_TEST_BROWSER_ACCESSIBILITY_H_
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc index a69ae599..93a3a8d 100644 --- a/content/public/test/browser_test_utils.cc +++ b/content/public/test/browser_test_utils.cc
@@ -89,6 +89,7 @@ #include "content/public/test/test_fileapi_operation_waiter.h" #include "content/public/test/test_launcher.h" #include "content/public/test/test_navigation_observer.h" +#include "content/test/browser_accessibility.h" #include "content/test/did_commit_navigation_interceptor.h" #include "ipc/ipc_security_test_util.h" #include "mojo/public/cpp/bindings/pending_remote.h" @@ -2027,39 +2028,42 @@ return manager->SnapshotAXTreeForTesting(); } -BrowserAccessibility* GetRootAccessibilityNode(WebContents* web_contents) { +TestBrowserAccessibility* GetRootAccessibilityNode(WebContents* web_contents) { WebContentsImpl* web_contents_impl = static_cast<WebContentsImpl*>(web_contents); BrowserAccessibilityManager* manager = web_contents_impl->GetRootBrowserAccessibilityManager(); - return manager ? manager->GetRoot() : nullptr; + return manager ? ToTestBrowserAccessibility(manager->GetRoot()) : nullptr; } FindAccessibilityNodeCriteria::FindAccessibilityNodeCriteria() = default; FindAccessibilityNodeCriteria::~FindAccessibilityNodeCriteria() = default; -BrowserAccessibility* FindAccessibilityNode( +TestBrowserAccessibility* FindAccessibilityNode( WebContents* web_contents, const FindAccessibilityNodeCriteria& criteria) { - BrowserAccessibility* root = GetRootAccessibilityNode(web_contents); + TestBrowserAccessibility* root = GetRootAccessibilityNode(web_contents); CHECK(root); return FindAccessibilityNodeInSubtree(root, criteria); } -BrowserAccessibility* FindAccessibilityNodeInSubtree( - BrowserAccessibility* node, +TestBrowserAccessibility* FindAccessibilityNodeInSubtree( + TestBrowserAccessibility* node, const FindAccessibilityNodeCriteria& criteria) { + BrowserAccessibility* node_internal = FromTestBrowserAccessibility(node); if ((!criteria.name || - node->GetStringAttribute(ax::mojom::StringAttribute::kName) == + node_internal->GetStringAttribute(ax::mojom::StringAttribute::kName) == criteria.name.value()) && - (!criteria.role || node->GetRole() == criteria.role.value())) { + (!criteria.role || node_internal->GetRole() == criteria.role.value())) { return node; } - for (unsigned int i = 0; i < node->PlatformChildCount(); ++i) { - BrowserAccessibility* result = - FindAccessibilityNodeInSubtree(node->PlatformGetChild(i), criteria); + for (unsigned int i = 0; i < node_internal->PlatformChildCount(); ++i) { + TestBrowserAccessibility* child = + ToTestBrowserAccessibility(node_internal->PlatformGetChild(i)); + TestBrowserAccessibility* result = + FindAccessibilityNodeInSubtree(child, criteria); if (result) return result; } @@ -2069,7 +2073,7 @@ #if defined(OS_WIN) template <typename T> Microsoft::WRL::ComPtr<T> QueryInterfaceFromNode( - BrowserAccessibility* browser_accessibility) { + TestBrowserAccessibility* browser_accessibility) { Microsoft::WRL::ComPtr<T> result; EXPECT_HRESULT_SUCCEEDED( browser_accessibility->GetNativeViewAccessible()->QueryInterface( @@ -2079,7 +2083,7 @@ void UiaGetPropertyValueVtArrayVtUnknownValidate( PROPERTYID property_id, - BrowserAccessibility* target_browser_accessibility, + TestBrowserAccessibility* target_browser_accessibility, const std::vector<std::string>& expected_names) { ASSERT_NE(nullptr, target_browser_accessibility); @@ -3154,7 +3158,7 @@ // exposing them in the header. class EvictionStateWaiter : public DelegatedFrameHost::Observer { public: - EvictionStateWaiter(DelegatedFrameHost* delegated_frame_host) + explicit EvictionStateWaiter(DelegatedFrameHost* delegated_frame_host) : delegated_frame_host_(delegated_frame_host) { delegated_frame_host_->AddObserverForTesting(this); }
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h index cdb6bc7..eeb3447 100644 --- a/content/public/test/browser_test_utils.h +++ b/content/public/test/browser_test_utils.h
@@ -89,7 +89,6 @@ namespace content { -class BrowserAccessibility; class BrowserContext; struct FrameVisualProperties; class FrameTreeNode; @@ -100,6 +99,7 @@ class RenderWidgetHost; class RenderWidgetHostView; class ScopedAllowRendererCrashes; +class TestBrowserAccessibility; class WebContents; // Navigates |web_contents| to |url|, blocking until the navigation finishes. @@ -909,7 +909,7 @@ ui::AXTreeUpdate GetAccessibilityTreeSnapshot(WebContents* web_contents); // Returns the root accessibility node for the given WebContents. -BrowserAccessibility* GetRootAccessibilityNode(WebContents* web_contents); +TestBrowserAccessibility* GetRootAccessibilityNode(WebContents* web_contents); // Finds an accessibility node matching the given criteria. struct FindAccessibilityNodeCriteria { @@ -918,18 +918,18 @@ base::Optional<ax::mojom::Role> role; base::Optional<std::string> name; }; -BrowserAccessibility* FindAccessibilityNode( +TestBrowserAccessibility* FindAccessibilityNode( WebContents* web_contents, const FindAccessibilityNodeCriteria& criteria); -BrowserAccessibility* FindAccessibilityNodeInSubtree( - BrowserAccessibility* node, +TestBrowserAccessibility* FindAccessibilityNodeInSubtree( + TestBrowserAccessibility* node, const FindAccessibilityNodeCriteria& criteria); #if defined(OS_WIN) // Retrieve the specified interface from an accessibility node. template <typename T> Microsoft::WRL::ComPtr<T> QueryInterfaceFromNode( - BrowserAccessibility* browser_accessibility); + TestBrowserAccessibility* browser_accessibility); // Call GetPropertyValue with the given UIA property id with variant type // VT_ARRAY | VT_UNKNOWN on the target browser accessibility node to retrieve @@ -937,7 +937,7 @@ // automation elements with the expected names. void UiaGetPropertyValueVtArrayVtUnknownValidate( PROPERTYID property_id, - BrowserAccessibility* target_browser_accessibility, + TestBrowserAccessibility* target_browser_accessibility, const std::vector<std::string>& expected_names); #endif
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index f496c51..950424b 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -99,6 +99,7 @@ "../public/test/background_sync_test_util.h", "../public/test/blink_test_environment.cc", "../public/test/blink_test_environment.h", + "../public/test/browser_accessibility.h", "../public/test/browser_side_navigation_test_utils.cc", "../public/test/browser_side_navigation_test_utils.h", "../public/test/browser_task_environment.cc", @@ -232,6 +233,8 @@ "../public/test/web_contents_tester.h", "appcache_test_helper.cc", "appcache_test_helper.h", + "browser_accessibility.cc", + "browser_accessibility.h", "content_browser_sanity_checker.cc", "content_browser_sanity_checker.h", "content_test_suite.cc",
diff --git a/content/test/browser_accessibility.cc b/content/test/browser_accessibility.cc new file mode 100644 index 0000000..61bd0f2 --- /dev/null +++ b/content/test/browser_accessibility.cc
@@ -0,0 +1,33 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/test/browser_accessibility.h" + +#include "content/browser/accessibility/accessibility_tree_formatter_base.h" + +namespace content { + +// static +void TestBrowserAccessibility::FormatAccessibilityTree( + AccessibilityTreeFormatter* formatter, + TestBrowserAccessibility* root, + base::string16* contents) { + auto* formatter_internal = + static_cast<AccessibilityTreeFormatterBase*>(formatter); + BrowserAccessibility* root_internal = FromTestBrowserAccessibility(root); + formatter_internal->FormatAccessibilityTreeForTesting(root_internal, + contents); +} + +TestBrowserAccessibility* ToTestBrowserAccessibility( + BrowserAccessibility* browser_accessibility) { + return reinterpret_cast<TestBrowserAccessibility*>(browser_accessibility); +} + +BrowserAccessibility* FromTestBrowserAccessibility( + TestBrowserAccessibility* test_browser_accessibility) { + return reinterpret_cast<BrowserAccessibility*>(test_browser_accessibility); +} + +} // namespace content
diff --git a/content/test/browser_accessibility.h b/content/test/browser_accessibility.h new file mode 100644 index 0000000..cba2d37 --- /dev/null +++ b/content/test/browser_accessibility.h
@@ -0,0 +1,23 @@ +// 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. + +#ifndef CONTENT_TEST_BROWSER_ACCESSIBILITY_H_ +#define CONTENT_TEST_BROWSER_ACCESSIBILITY_H_ + +#include "content/public/test/browser_accessibility.h" + +namespace content { + +class BrowserAccessibility; + +// Helper functions that are implementation details that should not be exposed +// via content/public/test/browser_accessibility.h. +TestBrowserAccessibility* ToTestBrowserAccessibility( + BrowserAccessibility* browser_accessibility); +BrowserAccessibility* FromTestBrowserAccessibility( + TestBrowserAccessibility* test_browser_accessibility); + +} // namespace content + +#endif // CONTENT_TEST_BROWSER_ACCESSIBILITY_H_
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android.txt new file mode 100644 index 0000000..774f065 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-android.txt
@@ -0,0 +1,5 @@ +android.webkit.WebView focusable focused scrollable +++android.view.View role_description='tree' collection hierarchical item_count=2 row_count=2 +++++android.view.View role_description='tree item' clickable collection_item focusable name='card content' +++++android.view.View +++++android.view.View role_description='tree item' clickable collection_item focusable name='card content' item_index=1 row_index=1 \ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-auralinux.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-auralinux.txt new file mode 100644 index 0000000..338497e7 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-auralinux.txt
@@ -0,0 +1,7 @@ +[document web] +++[tree] setsize:2 +++++[tree item] name='card content' selectable level:1 posinset:1 setsize:2 +++++++[static] name='card content' +++++[section] +++++[tree item] name='card content' selectable level:1 posinset:2 setsize:2 +++++++[static] name='card content' \ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-blink.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-blink.txt new file mode 100644 index 0000000..911dcb3 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-blink.txt
@@ -0,0 +1,10 @@ +rootWebArea +++genericContainer ignored +++++tree setSize=2 +++++++treeItem name='card content' hierarchicalLevel=1 setSize=2 posInSet=1 selected=false +++++++++staticText name='card content' +++++++++++inlineTextBox name='card content' +++++++genericContainer +++++++treeItem name='card content' hierarchicalLevel=1 setSize=2 posInSet=2 selected=false +++++++++staticText name='card content' +++++++++++inlineTextBox name='card content'
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-mac.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-mac.txt new file mode 100644 index 0000000..c4d1a17 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-mac.txt
@@ -0,0 +1,7 @@ +AXWebArea +++AXOutline AXARIASetSize='2' +++++AXRow AXTitle='card content' AXARIASetSize='2' AXARIAPosInSet='1' +++++++AXStaticText AXValue='card content' +++++AXGroup +++++AXRow AXTitle='card content' AXARIASetSize='2' AXARIAPosInSet='2' +++++++AXStaticText AXValue='card content' \ No newline at end of file
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-uia-win.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-uia-win.txt new file mode 100644 index 0000000..a3a5a247 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-uia-win.txt
@@ -0,0 +1,5 @@ +document PositionInSet=0 SizeOfSet=0 +++tree PositionInSet=0 SizeOfSet=2 Selection.CanSelectMultiple=false Selection.IsSelectionRequired=false +++++treeitem Name='card content' PositionInSet=1 SizeOfSet=2 ExpandCollapse.ExpandCollapseState='LeafNode' SelectionItem.IsSelected=false +++++group PositionInSet=0 SizeOfSet=0 +++++treeitem Name='card content' PositionInSet=2 SizeOfSet=2 ExpandCollapse.ExpandCollapseState='LeafNode' SelectionItem.IsSelected=false
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-win.txt b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-win.txt new file mode 100644 index 0000000..88a7d5c --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous-expected-win.txt
@@ -0,0 +1,7 @@ +ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE +++ROLE_SYSTEM_OUTLINE setsize:2 +++++ROLE_SYSTEM_OUTLINEITEM name='card content' FOCUSABLE setsize:2 posinset:1 +++++++ROLE_SYSTEM_STATICTEXT name='card content' +++++IA2_ROLE_SECTION +++++ROLE_SYSTEM_OUTLINEITEM name='card content' FOCUSABLE setsize:2 posinset:2 +++++++ROLE_SYSTEM_STATICTEXT name='card content'
diff --git a/content/test/data/accessibility/aria/aria-tree-discontinuous.html b/content/test/data/accessibility/aria/aria-tree-discontinuous.html new file mode 100644 index 0000000..1ec2bb3 --- /dev/null +++ b/content/test/data/accessibility/aria/aria-tree-discontinuous.html
@@ -0,0 +1,30 @@ +<!-- +@MAC-ALLOW:AXARIA* +@WIN-ALLOW:setsize* +@WIN-ALLOW:posinset* +@UIA-WIN-ALLOW:SizeOfSet* +@UIA-WIN-ALLOW:PositionInSet* +@AURALINUX-ALLOW:setsize* +@AURALINUX-ALLOW:posinset* +@AURALINUX-ALLOW:level* +@BLINK-ALLOW:hierarchicalLevel* +@BLINK-ALLOW:setSize* +@BLINK-ALLOW:posInSet* +--> +<!DOCTYPE html> +<html> + +<body> + + <div role="tree"> + <div role="treeitem" tabindex="0"> + card content + </div> + <div aria-hidden="false"></div> + <div role="treeitem" tabindex="0"> + card content + </div> + </div> +</body> + +</html>
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-android.txt b/content/test/data/accessibility/html/img-empty-alt-expected-android.txt index db07391..a358c0e 100644 --- a/content/test/data/accessibility/html/img-empty-alt-expected-android.txt +++ b/content/test/data/accessibility/html/img-empty-alt-expected-android.txt
@@ -1,6 +1,4 @@ android.webkit.WebView focusable focused scrollable ++android.view.View -++++android.widget.Image role_description='graphic' -++++android.widget.Image role_description='graphic' ++++android.widget.Image role_description='graphic' name='read' ++++android.widget.Image role_description='graphic' name='full'
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-auralinux.txt b/content/test/data/accessibility/html/img-empty-alt-expected-auralinux.txt index 3fec5e3..51e48e3e 100644 --- a/content/test/data/accessibility/html/img-empty-alt-expected-auralinux.txt +++ b/content/test/data/accessibility/html/img-empty-alt-expected-auralinux.txt
@@ -1,6 +1,4 @@ [document web] ++[section] -++++[image] name='' -++++[image] name='' ++++[image] ++++[image] name='full'
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt b/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt index d51d33a..177dc10 100644 --- a/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt +++ b/content/test/data/accessibility/html/img-empty-alt-expected-blink.txt
@@ -1,7 +1,7 @@ rootWebArea ++genericContainer ++++presentational ignored name='' -++++image name='' -++++image name='' +++++image ignored name='' +++++image ignored name='' ++++image ++++image name='full'
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt b/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt index 6677448c..02ee4d9 100644 --- a/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt +++ b/content/test/data/accessibility/html/img-empty-alt-expected-mac.txt
@@ -1,6 +1,4 @@ AXWebArea ++AXGroup -++++AXUnknown -++++AXUnknown ++++AXImage AXDescription='/read.jpg' ++++AXImage AXDescription='full'
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-uia-win.txt b/content/test/data/accessibility/html/img-empty-alt-expected-uia-win.txt index 221a798d2..c31fc910 100644 --- a/content/test/data/accessibility/html/img-empty-alt-expected-uia-win.txt +++ b/content/test/data/accessibility/html/img-empty-alt-expected-uia-win.txt
@@ -1,6 +1,4 @@ document ++group ++++img -++++img -++++img ++++img Name='full'
diff --git a/content/test/data/accessibility/html/img-empty-alt-expected-win.txt b/content/test/data/accessibility/html/img-empty-alt-expected-win.txt index 249ee03..deaa7dc 100644 --- a/content/test/data/accessibility/html/img-empty-alt-expected-win.txt +++ b/content/test/data/accessibility/html/img-empty-alt-expected-win.txt
@@ -1,6 +1,4 @@ ROLE_SYSTEM_DOCUMENT READONLY FOCUSABLE ++IA2_ROLE_SECTION -++++ROLE_SYSTEM_GRAPHIC name='' READONLY -++++ROLE_SYSTEM_GRAPHIC name='' READONLY ++++ROLE_SYSTEM_GRAPHIC READONLY ++++ROLE_SYSTEM_GRAPHIC name='full' READONLY
diff --git a/content/test/data/accessibility/html/img-expected-android.txt b/content/test/data/accessibility/html/img-expected-android.txt index 1d3eb951..724685b1 100644 --- a/content/test/data/accessibility/html/img-expected-android.txt +++ b/content/test/data/accessibility/html/img-expected-android.txt
@@ -2,6 +2,5 @@ ++android.view.View has_image ++++android.widget.Image role_description='graphic' has_image name='pipe' ++++android.view.View name=' ' -++++android.widget.Image role_description='graphic' has_image ++++android.view.View name=' ' ++++android.widget.Image role_description='graphic' has_image name=' '
diff --git a/content/test/data/accessibility/html/img-expected-auralinux.txt b/content/test/data/accessibility/html/img-expected-auralinux.txt index bf45e65..562b250 100644 --- a/content/test/data/accessibility/html/img-expected-auralinux.txt +++ b/content/test/data/accessibility/html/img-expected-auralinux.txt
@@ -2,6 +2,5 @@ ++[section] ++++[image] name='pipe' xml-roles:img ++++[static] name=' ' -++++[image] name='' xml-roles:img ++++[static] name=' ' -++++[image] name=' ' xml-roles:img +++++[image] name=' ' xml-roles:img \ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-expected-blink.txt b/content/test/data/accessibility/html/img-expected-blink.txt index 81b28d2..ff9ae73 100644 --- a/content/test/data/accessibility/html/img-expected-blink.txt +++ b/content/test/data/accessibility/html/img-expected-blink.txt
@@ -3,7 +3,6 @@ ++++image name='pipe' ++++staticText name=' ' ++++++inlineTextBox name=' ' -++++image name='' ++++staticText name=' ' ++++++inlineTextBox name=' ' ++++image name=' '
diff --git a/content/test/data/accessibility/html/img-expected-mac.txt b/content/test/data/accessibility/html/img-expected-mac.txt index a438c34..3ba7d011 100644 --- a/content/test/data/accessibility/html/img-expected-mac.txt +++ b/content/test/data/accessibility/html/img-expected-mac.txt
@@ -2,6 +2,5 @@ ++AXGroup ++++AXImage AXRoleDescription='image' AXDescription='pipe' ++++AXStaticText AXValue=' ' -++++AXUnknown ++++AXStaticText AXValue=' ' ++++AXImage AXRoleDescription='image' AXDescription=' ' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-expected-uia-win.txt b/content/test/data/accessibility/html/img-expected-uia-win.txt index 56321fb..97ffe28 100644 --- a/content/test/data/accessibility/html/img-expected-uia-win.txt +++ b/content/test/data/accessibility/html/img-expected-uia-win.txt
@@ -2,6 +2,5 @@ ++group ++++img Name='pipe' ++++description Name=' ' -++++img ++++description Name=' ' ++++img Name=' '
diff --git a/content/test/data/accessibility/html/img-expected-win.txt b/content/test/data/accessibility/html/img-expected-win.txt index ac8424f..af254395 100644 --- a/content/test/data/accessibility/html/img-expected-win.txt +++ b/content/test/data/accessibility/html/img-expected-win.txt
@@ -2,6 +2,5 @@ ++IA2_ROLE_SECTION ++++ROLE_SYSTEM_GRAPHIC name='pipe' READONLY xml-roles:img ++++ROLE_SYSTEM_STATICTEXT name=' ' -++++ROLE_SYSTEM_GRAPHIC name='' READONLY xml-roles:img ++++ROLE_SYSTEM_STATICTEXT name=' ' ++++ROLE_SYSTEM_GRAPHIC name=' ' READONLY xml-roles:img
diff --git a/content/test/data/accessibility/html/img-link-empty-alt-expected-auralinux.txt b/content/test/data/accessibility/html/img-link-empty-alt-expected-auralinux.txt index 2b16c3f..21b3c99 100644 --- a/content/test/data/accessibility/html/img-link-empty-alt-expected-auralinux.txt +++ b/content/test/data/accessibility/html/img-link-empty-alt-expected-auralinux.txt
@@ -3,11 +3,9 @@ ++++[link] name='unread ' ++++++[static] name='unread ' ++++[link] name='read ' -++++++[image] name='' ++++++[static] name='read ' ++++[link] name='read ' -++++++[image] name='' ++++++[static] name='read ' ++++[link] name='read' ++++++[image] -++++++[static] name='read' +++++++[static] name='read' \ No newline at end of file
diff --git a/content/test/data/accessibility/html/img-link-empty-alt-expected-blink.txt b/content/test/data/accessibility/html/img-link-empty-alt-expected-blink.txt index b2d8f10b..5671b2b6 100644 --- a/content/test/data/accessibility/html/img-link-empty-alt-expected-blink.txt +++ b/content/test/data/accessibility/html/img-link-empty-alt-expected-blink.txt
@@ -5,11 +5,11 @@ ++++++staticText name='unread ' ++++++++inlineTextBox name='unread ' ++++link name='read ' -++++++image name='' +++++++image ignored name='' ++++++staticText name='read ' ++++++++inlineTextBox name='read ' ++++link name='read ' -++++++image name='' +++++++image ignored name='' ++++++staticText name='read ' ++++++++inlineTextBox name='read ' ++++link name='read'
diff --git a/content/test/data/accessibility/html/img-link-empty-alt-expected-mac.txt b/content/test/data/accessibility/html/img-link-empty-alt-expected-mac.txt index e446d47..8034c1d 100644 --- a/content/test/data/accessibility/html/img-link-empty-alt-expected-mac.txt +++ b/content/test/data/accessibility/html/img-link-empty-alt-expected-mac.txt
@@ -3,10 +3,8 @@ ++++AXLink AXTitle='unread ' ++++++AXStaticText AXValue='unread ' ++++AXLink AXTitle='read ' -++++++AXUnknown ++++++AXStaticText AXValue='read ' ++++AXLink AXTitle='read ' -++++++AXUnknown ++++++AXStaticText AXValue='read ' ++++AXLink AXTitle='read' ++++++AXImage AXDescription='/read.jpg'
diff --git a/content/test/data/accessibility/html/img-link-empty-alt-expected-uia-win.txt b/content/test/data/accessibility/html/img-link-empty-alt-expected-uia-win.txt index a44e743..76b1408 100644 --- a/content/test/data/accessibility/html/img-link-empty-alt-expected-uia-win.txt +++ b/content/test/data/accessibility/html/img-link-empty-alt-expected-uia-win.txt
@@ -2,8 +2,6 @@ ++group ++++link Name='unread ' ++++link Name='read ' -++++++img ++++link Name='read ' -++++++img ++++link Name='read' ++++++img
diff --git a/content/test/data/accessibility/html/img-link-empty-alt-expected-win.txt b/content/test/data/accessibility/html/img-link-empty-alt-expected-win.txt index b2ee6926..f25a244 100644 --- a/content/test/data/accessibility/html/img-link-empty-alt-expected-win.txt +++ b/content/test/data/accessibility/html/img-link-empty-alt-expected-win.txt
@@ -3,10 +3,8 @@ ++++ROLE_SYSTEM_LINK name='unread ' FOCUSABLE ++++++ROLE_SYSTEM_STATICTEXT name='unread ' ++++ROLE_SYSTEM_LINK name='read ' FOCUSABLE -++++++ROLE_SYSTEM_GRAPHIC name='' READONLY ++++++ROLE_SYSTEM_STATICTEXT name='read ' ++++ROLE_SYSTEM_LINK name='read ' FOCUSABLE -++++++ROLE_SYSTEM_GRAPHIC name='' READONLY ++++++ROLE_SYSTEM_STATICTEXT name='read ' ++++ROLE_SYSTEM_LINK name='read' FOCUSABLE ++++++ROLE_SYSTEM_GRAPHIC READONLY
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn index e116e7a..2670b19 100644 --- a/device/vr/BUILD.gn +++ b/device/vr/BUILD.gn
@@ -65,7 +65,6 @@ "android/gvr/gvr_device.h", "android/gvr/gvr_device_provider.cc", "android/gvr/gvr_device_provider.h", - "android/gvr/gvr_gamepad_data_provider.h", "android/gvr/gvr_utils.cc", "android/gvr/gvr_utils.h", ]
diff --git a/device/vr/android/gvr/gvr_gamepad_data_provider.h b/device/vr/android/gvr/gvr_gamepad_data_provider.h deleted file mode 100644 index 8b3c0255..0000000 --- a/device/vr/android/gvr/gvr_gamepad_data_provider.h +++ /dev/null
@@ -1,71 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef DEVICE_VR_ANDROID_GVR_GVR_GAMEPAD_DATA_PROVIDER_H_ -#define DEVICE_VR_ANDROID_GVR_GVR_GAMEPAD_DATA_PROVIDER_H_ - -#include "ui/gfx/geometry/quaternion.h" -#include "ui/gfx/geometry/vector2d_f.h" -#include "ui/gfx/geometry/vector3d_f.h" - -namespace device { - -class GvrGamepadDataFetcher; - -// Subset of GVR controller data needed for the gamepad API. Filled in -// by vr_shell's VrController and consumed by GvrGamepadDataFetcher. -struct GvrGamepadData { - GvrGamepadData() - : timestamp(0), - is_touching(false), - controller_button_pressed(false), - right_handed(true), - connected(false) {} - int64_t timestamp; - gfx::Vector2dF touch_pos; - gfx::Quaternion orientation; - gfx::Vector3dF accel; - gfx::Vector3dF gyro; - bool is_touching; - bool controller_button_pressed; - bool right_handed; - bool connected; -}; - -// This class exposes GVR controller data to the gamepad API. Data is -// polled by GvrSchedulerDelegate, then pushed from VrShell which implements the -// GvrGamepadDataProvider interface. -// -// More specifically, here's the lifecycle, assuming VrShell -// implements GvrGamepadDataProvider: -// -// - VrShell creates GvrGamepadDataFetcherFactory from -// VrShell::UpdateGamepadData. -// -// - GvrGamepadDataFetcherFactory creates GvrGamepadDataFetcher. -// -// - GvrGamepadDataFetcher registers itself with VrShell via -// VrShell::RegisterGamepadDataFetcher. -// -// - While presenting, VrShell::UpdateGamepadData calls -// GvrGamepadDataFetcher->SetGamepadData to push poses, -// GvrGamepadDataFetcher::GetGamepadData returns these when polled. -// -// - VrShell starts executing its destructor. -// -// - VrShell destructor unregisters GvrGamepadDataFetcherFactory. -// -// - GvrGamepadDataFetcherFactory destructor destroys GvrGamepadDataFetcher. -// -class GvrGamepadDataProvider { - public: - // Refresh current GVR controller data for use by gamepad API. The - // implementation also lazily creates and registers the GVR - // GamepadDataFetcherFactory with the GamepadDataFetcherManager as - // needed. - virtual void UpdateGamepadData(GvrGamepadData data) = 0; -}; - -} // namespace device -#endif // DEVICE_VR_ANDROID_GVR_GVR_GAMEPAD_DATA_PROVIDER_H_
diff --git a/docs/speed/binary_size/optimization_advice.md b/docs/speed/binary_size/optimization_advice.md index db7857a..d300dd3a 100644 --- a/docs/speed/binary_size/optimization_advice.md +++ b/docs/speed/binary_size/optimization_advice.md
@@ -90,12 +90,12 @@ the [android-binary-size trybot][size-trybot]. * Or use [//tools/binary_size/diagnose_bloat.py][diagnose_bloat] to create diffs locally. - * Ensure no symbols exists that are used only by tests. + * Ensure no symbols exist that are used only by tests. * Be concise with strings used for error handling. * Identical strings throughout the codebase are de-duped. Take advantage of this for error-related strings. -### Optimizating Native Code +### Optimizing Native Code * If there's a notable increase in `.data.rel.ro`: * Ensure there are not [excessive relocations][relocations]. * If there's a notable increase in `.rodata`: @@ -112,7 +112,7 @@ * E.g. Use PODs wherever possible, and especially in containers. They will likely compile down to the same code as other pre-existing PODs. * Try also to use consistent field ordering within PODs. - * E.g. a `std::vector` of bare pointers will very likely by ICF'ed, but one + * E.g. a `std::vector` of bare pointers will very likely be ICF'ed, but one that uses smart pointers gets type-specific destructor logic inlined into it. * This advice is especially applicable to generated code. @@ -125,7 +125,7 @@ separate `const char *` and `const std::string&` overloads rather than a single `base::StringPiece`. -### Optimizating Java Code +### Optimizing Java Code * Prefer fewer large JNI calls over many small JNI calls. * Minimize the use of class initializers (`<clinit>()`). * If R8 cannot determine that they are "trivial", they will prevent @@ -150,7 +150,7 @@ single `onChanged()` that assumes everything changed. * Ensure unused code is optimized away by ProGuard / R8. * Add `@CheckDiscard` to methods or classes that you expect R8 to inline. - * Add `@RemovableInRelease` to force a method to be a no-op in when DCHECKs + * Add `@RemovableInRelease` to force a method to be a no-op when DCHECKs are disabled. * See [here][proguard-build-doc] for more info on how Chrome uses ProGuard.
diff --git a/extensions/renderer/resources/guest_view/guest_view_container_element.js b/extensions/renderer/resources/guest_view/guest_view_container_element.js index 7dae2c3..317a0b6 100644 --- a/extensions/renderer/resources/guest_view/guest_view_container_element.js +++ b/extensions/renderer/resources/guest_view/guest_view_container_element.js
@@ -15,20 +15,11 @@ var IdGenerator = requireNative('id_generator'); var logging = requireNative('logging'); -// Registers the browserplugin and guestview as custom elements once the -// document has loaded. +// Registers the browserplugin and guestview as custom elements. // |containerElementType| is a GuestViewContainerElement (e.g. WebViewElement) function registerElement(elementName, containerElementType) { - var useCapture = true; - window.addEventListener('readystatechange', function listener(event) { - if (document.readyState == 'loading') - return; - - registerInternalElement($String.toLowerCase(elementName)); - registerGuestViewElement(elementName, containerElementType); - - $EventTarget.removeEventListener(window, event.type, listener, useCapture); - }, useCapture); + registerInternalElement($String.toLowerCase(elementName)); + registerGuestViewElement(elementName, containerElementType); } // Registers the browser plugin <object> custom element. |viewType| is the
diff --git a/extensions/renderer/resources/guest_view/guest_view_deny.js b/extensions/renderer/resources/guest_view/guest_view_deny.js index b3961b5..1d43703 100644 --- a/extensions/renderer/resources/guest_view/guest_view_deny.js +++ b/extensions/renderer/resources/guest_view/guest_view_deny.js
@@ -11,7 +11,35 @@ var $EventTarget = require('safeMethods').SafeMethods.$EventTarget; var GuestViewInternalNatives = requireNative('guest_view_internal'); -function registerDeniedElementInternal(viewType, permissionName) { +// Once the document has loaded, expose the error-providing element's +// constructor to user code via |window|. +// GuestView elements used to be defined only once the document had loaded (see +// https://crbug.com/810012). This has been fixed, but as seen in +// https://crbug.com/1014385, user code that does not have permission for a +// GuestView could be using the same name for another purpose. In order to avoid +// potential name collisions with user code, we preserve the previous +// asynchronous behaviour for exposing the constructor of the error-providing +// element via |window|. +function asyncProvideElementConstructor(viewType, elementConstructor) { + let useCapture = true; + window.addEventListener('readystatechange', function listener(event) { + if (document.readyState == 'loading') + return; + + // If user code did use the name, we won't overwrite with the + // error-providing element. + if (!$Object.hasOwnProperty(window, viewType)) { + $Object.defineProperty(window, viewType, { + value: elementConstructor, + }); + } + + $EventTarget.removeEventListener(window, event.type, listener, useCapture); + }, useCapture); +} + +// Registers an error-providing GuestView custom element. +function registerDeniedElement(viewType, permissionName) { GuestViewInternalNatives.AllowGuestViewElementDefinition(() => { var DeniedElement = class extends HTMLElement { constructor() { @@ -23,29 +51,9 @@ } $CustomElementRegistry.define( window.customElements, $String.toLowerCase(viewType), DeniedElement); - // User code that does not have permission for this GuestView could be - // using the same name for another purpose, in which case we won't overwrite - // with the error-providing element. - if (!$Object.hasOwnProperty(window, viewType)) { - $Object.defineProperty(window, viewType, { - value: DeniedElement, - }); - } + asyncProvideElementConstructor(viewType, DeniedElement); }); } -// Registers an error-providing GuestView custom element. -function registerDeniedElement(viewType, permissionName) { - let useCapture = true; - window.addEventListener('readystatechange', function listener(event) { - if (document.readyState == 'loading') - return; - - registerDeniedElementInternal(viewType, permissionName); - - $EventTarget.removeEventListener(window, event.type, listener, useCapture); - }, useCapture); -} - // Exports. exports.$set('registerDeniedElement', registerDeniedElement);
diff --git a/gpu/ipc/client/image_decode_accelerator_proxy.h b/gpu/ipc/client/image_decode_accelerator_proxy.h index a47df5d..3c50e47 100644 --- a/gpu/ipc/client/image_decode_accelerator_proxy.h +++ b/gpu/ipc/client/image_decode_accelerator_proxy.h
@@ -53,7 +53,6 @@ // Determines if |image_metadata| corresponds to an image that can be decoded // using hardware decode acceleration. The ScheduleImageDecode() method should // only be called for images for which IsImageSupported() returns true. - // Otherwise, the client faces a GPU channel teardown if the decode fails. bool IsImageSupported( const cc::ImageHeaderMetadata* image_metadata) const override;
diff --git a/gpu/ipc/service/image_decode_accelerator_stub.cc b/gpu/ipc/service/image_decode_accelerator_stub.cc index 21aa72df..f61a9798e 100644 --- a/gpu/ipc/service/image_decode_accelerator_stub.cc +++ b/gpu/ipc/service/image_decode_accelerator_stub.cc
@@ -153,27 +153,11 @@ uint64_t release_count) { DCHECK(io_task_runner_->BelongsToCurrentThread()); base::AutoLock lock(lock_); - if (!channel_ || destroying_channel_) { + if (!channel_) { // The channel is no longer available, so don't do anything. return; } - // Make sure the decode sync token is ordered with respect to the last decode - // request. - if (release_count <= last_release_count_) { - DLOG(ERROR) << "Out-of-order decode sync token"; - OnError(); - return; - } - last_release_count_ = release_count; - - // Make sure the output dimensions are not too small. - if (decode_params.output_size.IsEmpty()) { - DLOG(ERROR) << "Output dimensions are too small"; - OnError(); - return; - } - // Start the actual decode. worker_->Decode( std::move(decode_params.encoded_data), decode_params.output_size, @@ -200,7 +184,7 @@ uint64_t decode_release_count) { DCHECK(main_task_runner_->BelongsToCurrentThread()); base::AutoLock lock(lock_); - if (!channel_ || destroying_channel_) { + if (!channel_) { // The channel is no longer available, so don't do anything. return; } @@ -208,6 +192,29 @@ DCHECK(!pending_completed_decodes_.empty()); std::unique_ptr<ImageDecodeAcceleratorWorker::DecodeResult> completed_decode = std::move(pending_completed_decodes_.front()); + pending_completed_decodes_.pop(); + + // Regardless of what happens next, make sure the sync token gets released and + // the sequence gets disabled if there are no more completed decodes after + // this. base::Unretained(this) is safe because *this outlives the + // ScopedClosureRunner. + base::ScopedClosureRunner finalizer( + base::BindOnce(&ImageDecodeAcceleratorStub::FinishCompletedDecode, + base::Unretained(this), decode_release_count)); + + if (!completed_decode) { + DLOG(ERROR) << "The image could not be decoded"; + return; + } + + // TODO(crbug.com/995883): the output_size parameter is going away, so this + // validation is not needed. Checking if the size is too small should happen + // at the level of the decoder (since that's the component that's aware of its + // own capabilities). + if (params.output_size.IsEmpty()) { + DLOG(ERROR) << "Output dimensions are too small"; + return; + } // Gain access to the transfer cache through the GpuChannelManager's // SharedContextState. We will also use that to get a GrContext that will be @@ -217,7 +224,6 @@ channel_->gpu_channel_manager()->GetSharedContextState(&context_result); if (context_result != ContextResult::kSuccess) { DLOG(ERROR) << "Unable to obtain the SharedContextState"; - OnError(); return; } DCHECK(shared_context_state); @@ -227,17 +233,14 @@ // other graphics APIs). if (!shared_context_state->IsGLInitialized()) { DLOG(ERROR) << "GL has not been initialized"; - OnError(); return; } if (!shared_context_state->gr_context()) { DLOG(ERROR) << "Could not get the GrContext"; - OnError(); return; } if (!shared_context_state->MakeCurrent(nullptr /* surface */)) { DLOG(ERROR) << "Could not MakeCurrent the shared context"; - OnError(); return; } @@ -269,7 +272,6 @@ if (!safe_uv_width.AssignIfValid(&uv_width) || !safe_uv_height.AssignIfValid(&uv_height)) { DLOG(ERROR) << "Could not calculate subsampled dimensions"; - OnError(); return; } gfx::Size uv_plane_size = gfx::Size(uv_width, uv_height); @@ -343,13 +345,11 @@ } if (!plane_image) { DLOG(ERROR) << "Could not create GL image"; - OnError(); return; } resource->gl_image = std::move(plane_image); if (!resource->gl_image->BindTexImage(GL_TEXTURE_EXTERNAL_OES)) { DLOG(ERROR) << "Could not bind GL image to texture"; - OnError(); return; } @@ -372,7 +372,6 @@ resource); if (!plane_sk_images[plane]) { DLOG(ERROR) << "Could not create planar SkImage"; - OnError(); return; } // No need for us to call the resource cleaner. Skia should do that. @@ -383,7 +382,6 @@ // |native_pixmap_handle| member of a GpuMemoryBufferHandle. NOTIMPLEMENTED() << "Image decode acceleration is unsupported for this platform"; - OnError(); return; #endif @@ -395,7 +393,6 @@ channel_->LookupCommandBuffer(params.raster_decoder_route_id); if (!command_buffer) { DLOG(ERROR) << "Could not find the command buffer"; - OnError(); return; } scoped_refptr<Buffer> handle_buffer = @@ -403,13 +400,11 @@ if (!DiscardableHandleBase::ValidateParameters( handle_buffer.get(), params.discardable_handle_shm_offset)) { DLOG(ERROR) << "Could not validate the discardable handle parameters"; - OnError(); return; } DCHECK(command_buffer->decoder_context()); if (command_buffer->decoder_context()->GetRasterDecoderId() < 0) { DLOG(ERROR) << "Could not get the raster decoder ID"; - OnError(); return; } @@ -441,21 +436,18 @@ completed_decode->yuv_color_space, completed_decode->buffer_byte_size, params.needs_mips)) { DLOG(ERROR) << "Could not create and insert the transfer cache entry"; - OnError(); return; } } DCHECK(notify_gl_state_changed); notify_gl_state_changed->RunAndReset(); +} - // All done! The decoded image can now be used for rasterization, so we can - // release the decode sync token. +void ImageDecodeAcceleratorStub::FinishCompletedDecode( + uint64_t decode_release_count) { + DCHECK(main_task_runner_->BelongsToCurrentThread()); + lock_.AssertAcquired(); sync_point_client_state_->ReleaseFenceSync(decode_release_count); - - // If there are no more completed decodes to be processed, we can disable the - // sequence: when the next decode is completed, the sequence will be - // re-enabled. - pending_completed_decodes_.pop(); if (pending_completed_decodes_.empty()) channel_->scheduler()->DisableSequence(sequence_); } @@ -464,19 +456,13 @@ gfx::Size expected_output_size, std::unique_ptr<ImageDecodeAcceleratorWorker::DecodeResult> result) { base::AutoLock lock(lock_); - if (!channel_ || destroying_channel_) { + if (!channel_) { // The channel is no longer available, so don't do anything. return; } - if (!result) { - DLOG(ERROR) << "The decode failed"; - OnError(); - return; - } - // A sanity check on the output of the decoder. - DCHECK(expected_output_size == result->visible_size); + DCHECK(!result || expected_output_size == result->visible_size); // The decode is ready to be processed: add it to |pending_completed_decodes_| // so that ProcessCompletedDecode() can pick it up. @@ -488,19 +474,4 @@ channel_->scheduler()->EnableSequence(sequence_); } -void ImageDecodeAcceleratorStub::OnError() { - lock_.AssertAcquired(); - DCHECK(channel_); - - // Trigger the destruction of the channel and stop processing further - // completed decodes, even if they're successful. We can't call - // GpuChannel::OnChannelError() directly because that will end up calling - // ImageDecodeAcceleratorStub::Shutdown() while |lock_| is still acquired. So, - // we post a task to the main thread instead. - destroying_channel_ = true; - channel_->task_runner()->PostTask( - FROM_HERE, - base::BindOnce(&GpuChannel::OnChannelError, channel_->AsWeakPtr())); -} - } // namespace gpu
diff --git a/gpu/ipc/service/image_decode_accelerator_stub.h b/gpu/ipc/service/image_decode_accelerator_stub.h index 41256a30..b3552f9 100644 --- a/gpu/ipc/service/image_decode_accelerator_stub.h +++ b/gpu/ipc/service/image_decode_accelerator_stub.h
@@ -76,23 +76,22 @@ uint64_t release_count); // Creates the service-side cache entry for a completed decode and releases - // the decode sync token. + // the decode sync token. If the decode was unsuccessful, no cache entry is + // created but the decode sync token is still released. void ProcessCompletedDecode(GpuChannelMsg_ScheduleImageDecode_Params params, uint64_t decode_release_count); - // The |worker_| calls this when a decode is completed. If the decode is - // successful, |sequence_| will be enabled so that ProcessCompletedDecode() is - // called. If the decode is not successful, we destroy the channel (see - // OnError()). + // Releases the decode sync token corresponding to |decode_release_count| and + // disables |sequence_| if there are no more decodes to process for now. + void FinishCompletedDecode(uint64_t decode_release_count) + EXCLUSIVE_LOCKS_REQUIRED(lock_); + + // The |worker_| calls this when a decode is completed. |result| is enqueued + // and |sequence_| is enabled so that ProcessCompletedDecode() picks it up. void OnDecodeCompleted( gfx::Size expected_output_size, std::unique_ptr<ImageDecodeAcceleratorWorker::DecodeResult> result); - // Triggers the destruction of the channel asynchronously and makes it so that - // we stop accepting completed decodes. On entry, |channel_| must not be - // nullptr. - void OnError() EXCLUSIVE_LOCKS_REQUIRED(lock_); - // The object to which the actual decoding can be delegated. ImageDecodeAcceleratorWorker* worker_ = nullptr; @@ -103,8 +102,6 @@ GUARDED_BY(lock_); base::queue<std::unique_ptr<ImageDecodeAcceleratorWorker::DecodeResult>> pending_completed_decodes_ GUARDED_BY(lock_); - bool destroying_channel_ GUARDED_BY(lock_) = false; - uint64_t last_release_count_ GUARDED_BY(lock_) = 0; ImageFactory* external_image_factory_for_testing_ = nullptr;
diff --git a/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc b/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc index 23830d15..2f88c3c 100644 --- a/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc +++ b/gpu/ipc/service/image_decode_accelerator_stub_unittest.cc
@@ -73,6 +73,11 @@ namespace { +struct ExpectedCacheEntry { + uint32_t id = 0u; + SkISize dimensions; +}; + std::unique_ptr<MemoryTracker> CreateMockMemoryTracker( const GPUCreateCommandBufferConfig& init_params) { return std::make_unique<gles2::MockMemoryTracker>(); @@ -204,8 +209,7 @@ int GetRasterDecoderId() { GpuChannel* channel = channel_manager()->LookupChannel(kChannelId); - if (!channel) - return -1; + DCHECK(channel); CommandBufferStub* command_buffer = channel->LookupCommandBuffer(kCommandBufferRouteId); if (!command_buffer || !command_buffer->decoder_context()) @@ -283,7 +287,7 @@ scoped_refptr<Buffer> buffer, uint64_t handle_release_count) { GpuChannel* channel = channel_manager()->LookupChannel(kChannelId); - CHECK(channel); + DCHECK(channel); CommandBufferStub* command_buffer = channel->LookupCommandBuffer(kCommandBufferRouteId); CHECK(command_buffer); @@ -295,12 +299,11 @@ // the raster sequence) to register the handle's buffer and release the sync // token corresponding to |handle_release_count| (see the // RegisterDiscardableHandleBuffer() method). Returns an invalid handle if the - // GPU channel or the command buffer doesn't exist. + // command buffer doesn't exist. ClientDiscardableHandle CreateDiscardableHandle( uint64_t handle_release_count) { GpuChannel* channel = channel_manager()->LookupChannel(kChannelId); - if (!channel) - return ClientDiscardableHandle(); + DCHECK(channel); CommandBufferStub* command_buffer = channel->LookupCommandBuffer(kCommandBufferRouteId); if (!command_buffer) @@ -324,20 +327,14 @@ // (|decode_release_count|), the transfer cache entry ID // (|transfer_cache_entry_id|), and the release count of the sync token that // is signaled after the discardable handle's buffer has been registered in - // the TransferBufferManager. If the channel does not exist or the discardable - // handle can't be created, this function returns an empty sync token. + // the TransferBufferManager. If the discardable handle can't be created, this + // function returns an empty sync token. SyncToken SendDecodeRequest(const gfx::Size& output_size, uint64_t decode_release_count, uint32_t transfer_cache_entry_id, uint64_t handle_release_count) { GpuChannel* channel = channel_manager()->LookupChannel(kChannelId); - if (!channel) { - // It's possible that the channel was destroyed as part of an earlier - // SendDecodeRequest() call. This would happen if - // ImageDecodeAcceleratorStub::OnScheduleImageDecode decides to destroy - // the channel. - return SyncToken(); - } + DCHECK(channel); // Create the decode sync token for the decode request so that we can test // that it's actually released. @@ -383,7 +380,8 @@ } } - void CheckTransferCacheEntries(std::vector<SkISize> expected_sizes) { + void CheckTransferCacheEntries( + const std::vector<ExpectedCacheEntry>& expected_entries) { ServiceTransferCache* transfer_cache = GetServiceTransferCache(); ASSERT_TRUE(transfer_cache); @@ -391,8 +389,8 @@ // expected. const size_t num_actual_cache_entries = transfer_cache->entries_count_for_testing(); - ASSERT_EQ(expected_sizes.size(), num_actual_cache_entries); - if (expected_sizes.empty()) + ASSERT_EQ(expected_entries.size(), num_actual_cache_entries); + if (expected_entries.empty()) return; // Then, check the dimensions of the entries to make sure they are as @@ -402,7 +400,8 @@ for (size_t i = 0; i < num_actual_cache_entries; i++) { auto* decode_entry = static_cast<cc::ServiceImageTransferCacheEntry*>( transfer_cache->GetEntry(ServiceTransferCache::EntryKey( - raster_decoder_id, cc::TransferCacheEntryType::kImage, i + 1))); + raster_decoder_id, cc::TransferCacheEntryType::kImage, + expected_entries[i].id))); ASSERT_TRUE(decode_entry); ASSERT_EQ(gfx::NumberOfPlanesForLinearBufferFormat(GetParam()), decode_entry->plane_images().size()); @@ -412,9 +411,9 @@ EXPECT_TRUE(decode_entry->plane_images()[plane]->isTextureBacked()); } ASSERT_TRUE(decode_entry->image()); - EXPECT_EQ(expected_sizes[i].width(), + EXPECT_EQ(expected_entries[i].dimensions.width(), decode_entry->image()->dimensions().width()); - EXPECT_EQ(expected_sizes[i].height(), + EXPECT_EQ(expected_entries[i].dimensions.height(), decode_entry->image()->dimensions().height()); } } @@ -471,11 +470,9 @@ EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode1_sync_token)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); - // The channel should still exist at the end. - EXPECT_TRUE(channel_manager()->LookupChannel(kChannelId)); - // Check that the decoded images are in the transfer cache. - CheckTransferCacheEntries({SkISize::Make(100, 100), SkISize::Make(200, 200)}); + CheckTransferCacheEntries( + {{1u, SkISize::Make(100, 100)}, {2u, SkISize::Make(200, 200)}}); } // Tests the following flow: three decode requests are sent. The first decode @@ -521,18 +518,14 @@ EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode3_sync_token)); - // The channel should still exist at the end. - EXPECT_TRUE(channel_manager()->LookupChannel(kChannelId)); - // Check that the decoded images are in the transfer cache. - CheckTransferCacheEntries({SkISize::Make(100, 100), SkISize::Make(200, 200), - SkISize::Make(300, 300)}); + CheckTransferCacheEntries({{1u, SkISize::Make(100, 100)}, + {2u, SkISize::Make(200, 200)}, + {3u, SkISize::Make(300, 300)}}); } // Tests the following flow: three decode requests are sent. The first decode -// fails which should trigger the destruction of the channel. The second -// succeeds and the third one fails. Regardless, the channel should still be -// destroyed and all sync tokens should be released. +// fails, the second succeeds, and the third one fails. TEST_P(ImageDecodeAcceleratorStubTest, FailedDecodes) { { InSequence call_sequence; @@ -561,25 +554,29 @@ EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode1_sync_token)); EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode3_sync_token)); + + // All decode sync tokens should be released after completing all the decodes. image_decode_accelerator_worker_.FinishOneDecode(false); image_decode_accelerator_worker_.FinishOneDecode(true); image_decode_accelerator_worker_.FinishOneDecode(false); - - // We expect the destruction of the ImageDecodeAcceleratorStub, which also - // implies that all decode sync tokens should be released. RunTasksUntilIdle(); - EXPECT_FALSE(channel_manager()->LookupChannel(kChannelId)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode1_sync_token)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode3_sync_token)); - // We expect no entries in the transfer cache. - CheckTransferCacheEntries({}); + // There should only be one image in the transfer cache (the one that + // succeeded). + CheckTransferCacheEntries({{2u, SkISize::Make(200, 200)}}); } TEST_P(ImageDecodeAcceleratorStubTest, OutOfOrderDecodeSyncTokens) { - EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(100, 100))) - .Times(1); + { + InSequence call_sequence; + EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(100, 100))) + .Times(1); + EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(200, 200))) + .Times(1); + } const SyncToken decode1_sync_token = SendDecodeRequest( gfx::Size(100, 100) /* output_size */, 2u /* decode_release_count */, 1u /* transfer_cache_entry_id */, 1u /* handle_release_count */); @@ -590,62 +587,87 @@ 2u /* transfer_cache_entry_id */, 2u /* handle_release_count */); ASSERT_TRUE(decode2_sync_token.HasData()); - // We expect the destruction of the ImageDecodeAcceleratorStub, which also - // implies that all decode sync tokens should be released. + // A decode sync token should not be released before a decode is finished. RunTasksUntilIdle(); - EXPECT_FALSE(channel_manager()->LookupChannel(kChannelId)); + EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode1_sync_token)); + EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); + + // Since the sync tokens are out of order, releasing the first one should also + // release the second one. + image_decode_accelerator_worker_.FinishOneDecode(true); + RunTasksUntilIdle(); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode1_sync_token)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); - // We expect no entries in the transfer cache. - CheckTransferCacheEntries({}); + // We only expect the first image in the transfer cache. + CheckTransferCacheEntries({{1u, SkISize::Make(100, 100)}}); + + // Finishing the second decode should not "unrelease" the first sync token. + image_decode_accelerator_worker_.FinishOneDecode(true); + RunTasksUntilIdle(); + EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode1_sync_token)); + EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode2_sync_token)); + CheckTransferCacheEntries( + {{1u, SkISize::Make(100, 100)}, {2u, SkISize::Make(200, 200)}}); } TEST_P(ImageDecodeAcceleratorStubTest, ZeroReleaseCountDecodeSyncToken) { + EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(100, 100))) + .Times(1); const SyncToken decode_sync_token = SendDecodeRequest( gfx::Size(100, 100) /* output_size */, 0u /* decode_release_count */, 1u /* transfer_cache_entry_id */, 1u /* handle_release_count */); ASSERT_TRUE(decode_sync_token.HasData()); - // We expect the destruction of the ImageDecodeAcceleratorStub, which also - // implies that all decode sync tokens should be released. + // A zero-release count sync token is always considered released. RunTasksUntilIdle(); - EXPECT_FALSE(channel_manager()->LookupChannel(kChannelId)); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); - // We expect no entries in the transfer cache. - CheckTransferCacheEntries({}); + // Even though the release count is not really valid, we can still finish the + // decode. + image_decode_accelerator_worker_.FinishOneDecode(true); + RunTasksUntilIdle(); + EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); + CheckTransferCacheEntries({{1u, SkISize::Make(100, 100)}}); } TEST_P(ImageDecodeAcceleratorStubTest, ZeroWidthOutputSize) { + EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(0, 100))) + .Times(1); const SyncToken decode_sync_token = SendDecodeRequest( gfx::Size(0, 100) /* output_size */, 1u /* decode_release_count */, 1u /* transfer_cache_entry_id */, 1u /* handle_release_count */); ASSERT_TRUE(decode_sync_token.HasData()); - // We expect the destruction of the ImageDecodeAcceleratorStub, which also - // implies that all decode sync tokens should be released. + // A decode sync token should not be released before a decode is finished. RunTasksUntilIdle(); - EXPECT_FALSE(channel_manager()->LookupChannel(kChannelId)); - EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); + EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); - // We expect no entries in the transfer cache. + // Even though the output size is not valid, we can still finish the decode. + // We just shouldn't get any entries in the transfer cache. + image_decode_accelerator_worker_.FinishOneDecode(true); + RunTasksUntilIdle(); + EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); CheckTransferCacheEntries({}); } TEST_P(ImageDecodeAcceleratorStubTest, ZeroHeightOutputSize) { + EXPECT_CALL(image_decode_accelerator_worker_, DoDecode(gfx::Size(100, 0))) + .Times(1); const SyncToken decode_sync_token = SendDecodeRequest( gfx::Size(100, 0) /* output_size */, 1u /* decode_release_count */, 1u /* transfer_cache_entry_id */, 1u /* handle_release_count */); ASSERT_TRUE(decode_sync_token.HasData()); - // We expect the destruction of the ImageDecodeAcceleratorStub, which also - // implies that all decode sync tokens should be released. + // A decode sync token should not be released before a decode is finished. RunTasksUntilIdle(); - EXPECT_FALSE(channel_manager()->LookupChannel(kChannelId)); - EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); + EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); - // We expect no entries in the transfer cache. + // Even though the output size is not valid, we can still finish the decode. + // We just shouldn't get any entries in the transfer cache. + image_decode_accelerator_worker_.FinishOneDecode(true); + RunTasksUntilIdle(); + EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); CheckTransferCacheEntries({}); } @@ -683,14 +705,6 @@ RunTasksUntilIdle(); EXPECT_FALSE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); - // Let's make sure that the channel and the command buffer are still alive - // because if we didn't wait for the discardable handle's buffer to be - // registered, we could have caused a channel teardown. - ASSERT_TRUE(channel_manager()->LookupChannel(kChannelId)); - ASSERT_TRUE(channel_manager() - ->LookupChannel(kChannelId) - ->LookupCommandBuffer(kCommandBufferRouteId)); - // Now let's register the discardable handle's buffer by re-enabling the // raster sequence. This should trigger the processing of the completed decode // and the subsequent release of the decode sync token. @@ -698,11 +712,8 @@ RunTasksUntilIdle(); EXPECT_TRUE(sync_point_manager()->IsSyncTokenReleased(decode_sync_token)); - // The channel should still exist at the end. - EXPECT_TRUE(channel_manager()->LookupChannel(kChannelId)); - // Check that the decoded images are in the transfer cache. - CheckTransferCacheEntries({SkISize::Make(100, 100)}); + CheckTransferCacheEntries({{1u, SkISize::Make(100, 100)}}); } // TODO(andrescj): test the deletion of transfer cache entries.
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h index 973c0a7..89ade2b 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.h
@@ -38,6 +38,7 @@ void InvalidateLine(size_t line) override {} void OnLineSelected(size_t line) override {} void UpdatePopupAppearance() override; + void ProvideButtonFocusHint(size_t line) override {} void OnMatchIconUpdated(size_t match_index) override {} void OnDragCanceled() override {}
diff --git a/ios/chrome/browser/ui/webui/BUILD.gn b/ios/chrome/browser/ui/webui/BUILD.gn index fb4b139..943a0d9 100644 --- a/ios/chrome/browser/ui/webui/BUILD.gn +++ b/ios/chrome/browser/ui/webui/BUILD.gn
@@ -121,6 +121,7 @@ source_set("eg_tests") { configs += [ "//build/config/compiler:enable_arc" ] + defines = [ "CHROME_EARL_GREY_1" ] testonly = true sources = [ "inspect/inspect_ui_egtest.mm", @@ -135,6 +136,7 @@ "//ios/chrome/browser/ui/omnibox:omnibox_internal", "//ios/chrome/test/app:test_support", "//ios/chrome/test/earl_grey:test_support", + "//ios/testing/earl_grey:earl_grey_support", "//ios/web", "//ios/web/public/test:element_selector", "//net:test_support", @@ -143,3 +145,25 @@ ] libs = [ "XCTest.framework" ] } + +source_set("eg2_tests") { + defines = [ "CHROME_EARL_GREY_2" ] + configs += [ + "//build/config/compiler:enable_arc", + "//build/config/ios:xctest_config", + ] + testonly = true + sources = [ + "inspect/inspect_ui_egtest.mm", + ] + deps = [ + "//base", + "//ios/chrome/browser:chrome_url_constants", + "//ios/chrome/test/earl_grey:eg_test_support+eg2", + "//ios/testing/earl_grey:eg_test_support+eg2", + "//ios/third_party/earl_grey2:test_lib", + "//ios/web/public/test:element_selector", + "//net:test_support", + ] + libs = [ "UIKit.framework" ] +}
diff --git a/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm b/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm index 0d5110e..40a2530a8 100644 --- a/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm +++ b/ios/chrome/browser/ui/webui/inspect/inspect_ui_egtest.mm
@@ -2,17 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import <EarlGrey/EarlGrey.h> #import <Foundation/Foundation.h> #import <XCTest/XCTest.h> #import "base/strings/sys_string_conversions.h" #include "ios/chrome/browser/chrome_url_constants.h" -#import "ios/chrome/test/app/tab_test_util.h" #import "ios/chrome/test/earl_grey/chrome_actions.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_matchers.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" +#import "ios/testing/earl_grey/earl_grey_test.h" #include "ios/web/public/test/element_selector.h" #include "net/test/embedded_test_server/embedded_test_server.h" @@ -20,8 +19,6 @@ #error "This file requires ARC support." #endif -using chrome_test_util::GetCurrentWebState; - namespace { // Directory containing the |kLogoPagePath| and |kLogoPageImageSourcePath| // resources.
diff --git a/ios/chrome/test/earl_grey2/BUILD.gn b/ios/chrome/test/earl_grey2/BUILD.gn index b0fc51a..2cf08e7 100644 --- a/ios/chrome/test/earl_grey2/BUILD.gn +++ b/ios/chrome/test/earl_grey2/BUILD.gn
@@ -89,6 +89,7 @@ "//ios/chrome/browser/ui/tab_grid:eg2_tests", "//ios/chrome/browser/ui/tabs:eg2_tests", "//ios/chrome/browser/ui/toolbar:eg2_tests", + "//ios/chrome/browser/ui/webui:eg2_tests", ] }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index 67b576da..6e358325 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -231,12 +231,8 @@ const base::Feature kMediaCastOverlayButton{"MediaCastOverlayButton", base::FEATURE_ENABLED_BY_DEFAULT}; -// Use AndroidOverlay rather than ContentVideoView in clank? -const base::Feature kUseAndroidOverlay{"UseAndroidOverlay", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Use AndroidOverlay for more cases than just player-element fullscreen? This -// requires that |kUseAndroidOverlay| is true, else it is ignored. +// requires that |kOverlayFullscreenVideo| is true, else it is ignored. const base::Feature kUseAndroidOverlayAggressively{ "UseAndroidOverlayAggressively", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index cf1197b4..027a4d6 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -140,7 +140,6 @@ MEDIA_EXPORT extern const base::Feature kRevokeMediaSourceObjectURLOnAttach; MEDIA_EXPORT extern const base::Feature kSpecCompliantCanPlayThrough; MEDIA_EXPORT extern const base::Feature kUnifiedAutoplay; -MEDIA_EXPORT extern const base::Feature kUseAndroidOverlay; MEDIA_EXPORT extern const base::Feature kUseAndroidOverlayAggressively; MEDIA_EXPORT extern const base::Feature kUseFakeDeviceForMediaStream; MEDIA_EXPORT extern const base::Feature kUseMediaHistoryStore;
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn index 7ec07f1..4643040 100644 --- a/media/blink/BUILD.gn +++ b/media/blink/BUILD.gn
@@ -39,6 +39,8 @@ "resource_fetch_context.h", "resource_multibuffer_data_provider.cc", "resource_multibuffer_data_provider.h", + "smoothness_helper.cc", + "smoothness_helper.h", "texttrack_impl.cc", "texttrack_impl.h", "url_index.cc", @@ -147,6 +149,7 @@ "multibuffer_unittest.cc", "resource_multibuffer_data_provider_unittest.cc", "run_all_unittests.cc", + "smoothness_helper_unittest.cc", "test_response_generator.cc", "test_response_generator.h", "url_index_unittest.cc",
diff --git a/media/blink/smoothness_helper.cc b/media/blink/smoothness_helper.cc new file mode 100644 index 0000000..76c530b --- /dev/null +++ b/media/blink/smoothness_helper.cc
@@ -0,0 +1,145 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/blink/smoothness_helper.h" + +#include "base/bind.h" +#include "base/optional.h" +#include "base/timer/timer.h" +#include "base/unguessable_token.h" +#include "media/learning/common/learning_task_controller.h" + +namespace { +static constexpr base::TimeDelta kSegmentSize = + base::TimeDelta::FromSeconds(60); +} + +namespace media { + +using learning::FeatureVector; +using learning::LearningTaskController; +using learning::TargetValue; + +class SmoothnessHelperImpl : public SmoothnessHelper { + public: + SmoothnessHelperImpl(std::unique_ptr<LearningTaskController> controller, + const FeatureVector& features, + Client* player) + : controller_(std::move(controller)), + features_(features), + player_(player) {} + + // This will ignore the last segment, if any, which is fine since it's not + // a complete segment. + ~SmoothnessHelperImpl() override = default; + + void NotifyPlayState(bool playing) override { + if (playing) { + if (segment_decoded_frames_) + return; + + // We're starting a new playback, so record the baseline frame counts. + segment_dropped_frames_ = player_->DroppedFrameCount(); + segment_decoded_frames_ = player_->DecodedFrameCount(); + worst_segment_during_playback_ = TargetValue(0); + + DCHECK(!id_); + + // Don't bother to start the observation until the timer fires, since we + // don't wanto to record short playbacks. + + update_timer_.Start(FROM_HERE, kSegmentSize, + base::BindRepeating(&SmoothnessHelperImpl::OnTimer, + base::Unretained(this))); + } else { + if (!segment_decoded_frames_) + return; + + // If we started an observation, then complete it. Otherwise, the segment + // wasn't long enough. Note that we also don't update the worst NNR + // rate here, so that we don't include very short partial segments that + // might be artificially high. Note that this might be a bad idea; if + // the site detects bad playback and adapts before we've measured one + // segment, then we'll never record those NNRs. We might want to allow + // the final segment to be smaller than |kSegmentSize|, as long as it's + // not too small. + if (id_) + controller_->CompleteObservation(*id_, worst_segment_during_playback_); + + // End the segment and the playback. + segment_decoded_frames_.reset(); + segment_dropped_frames_.reset(); + update_timer_.Stop(); + id_.reset(); + } + } + + // Split playback into segments of length |kSegmentSize|, and update the + // default value of the current playback. + void OnTimer() { + DCHECK(segment_decoded_frames_); + + auto new_dropped_frames = player_->DroppedFrameCount(); + auto dropped_frames = new_dropped_frames - *segment_dropped_frames_; + segment_dropped_frames_ = new_dropped_frames; + + auto new_decoded_frames = player_->DecodedFrameCount(); + auto decoded_frames = new_decoded_frames - *segment_decoded_frames_; + segment_decoded_frames_ = new_decoded_frames; + + if (!decoded_frames) + return; + + // The target value is just the percentage of dropped frames. + auto target = TargetValue(((double)dropped_frames) / decoded_frames); + + // See if this is worse than any previous segment. + if (target > worst_segment_during_playback_) + worst_segment_during_playback_ = target; + + // Start an observation for this playback, or update the default. + if (!id_) { + id_ = base::UnguessableToken::Create(); + controller_->BeginObservation(*id_, features_, + worst_segment_during_playback_); + } else { + controller_->UpdateDefaultTarget(*id_, worst_segment_during_playback_); + } + } + + // Current dropped, decoded frames at the start of the segment, if any. + base::Optional<int64_t> segment_decoded_frames_; + base::Optional<int64_t> segment_dropped_frames_; + + // Of all the segments in this playback, this is the worst NNR ratio. + TargetValue worst_segment_during_playback_; + + std::unique_ptr<LearningTaskController> controller_; + + FeatureVector features_; + + base::RepeatingTimer update_timer_; + + // WebMediaPlayer which will tell us about the decoded / dropped frame counts. + Client* player_; + + // If an observation is in progress, then this is the id. + base::Optional<base::UnguessableToken> id_; +}; + +// static +std::unique_ptr<SmoothnessHelper> SmoothnessHelper::Create( + std::unique_ptr<LearningTaskController> controller, + const FeatureVector& features, + Client* player) { + return std::make_unique<SmoothnessHelperImpl>(std::move(controller), features, + player); +} + +// static +base::TimeDelta SmoothnessHelper::SegmentSizeForTesting() { + return kSegmentSize; +} + +} // namespace media
diff --git a/media/blink/smoothness_helper.h b/media/blink/smoothness_helper.h new file mode 100644 index 0000000..02694a1 --- /dev/null +++ b/media/blink/smoothness_helper.h
@@ -0,0 +1,63 @@ +// 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. + +#ifndef MEDIA_BLINK_SMOOTHNESS_HELPER_H_ +#define MEDIA_BLINK_SMOOTHNESS_HELPER_H_ + +#include <memory> + +#include "media/base/buffering_state.h" +#include "media/base/pipeline_status.h" +#include "media/blink/media_blink_export.h" +#include "media/learning/common/labelled_example.h" + +namespace media { + +namespace learning { +class LearningTaskController; +} + +// Helper class to construct learning observations about the smoothness of a +// video playback. Currently measures the worst-case frame drop ratio observed +// among fixed-length segments. +class MEDIA_BLINK_EXPORT SmoothnessHelper { + public: + // Callback that provides the number of dropped / decoded frames since some + // point in the past. We assume that these values are comparable during + // playback, so that we can compute deltas. + class Client { + public: + virtual ~Client() {} + + virtual unsigned DecodedFrameCount() const = 0; + virtual unsigned DroppedFrameCount() const = 0; + }; + + virtual ~SmoothnessHelper() = default; + + // |features| are the features that we'll use for any labelled examples that + // we create. They should be features that could be captured at the time a + // prediction would be needed. + static std::unique_ptr<SmoothnessHelper> Create( + std::unique_ptr<learning::LearningTaskController> controller, + const learning::FeatureVector& features, + Client* player); + + // Notify us when we start or stop playing. + // TODO(liberato): There is an open question whether we'd like one call of + // the form "ThePlayerIsInTheRightStateToRecordSmoothness(bool)", or whether + // we'd like multiple calls to record the state of the player, like + // "SetIsPlaying", "SetIsBackgrounded", etc. The difference is whether the + // decision to record is made by the player or by us. + virtual void NotifyPlayState(bool playing) = 0; + + // We split playbacks up into |kSegmentSize| units, and record the worst + // dropped frame ratio over all segments of a playback. A playback is not + // recorded if it doesn't contain at least one full segment. + static base::TimeDelta SegmentSizeForTesting(); +}; + +} // namespace media + +#endif // MEDIA_BLINK_SMOOTHNESS_HELPER_H_
diff --git a/media/blink/smoothness_helper_unittest.cc b/media/blink/smoothness_helper_unittest.cc new file mode 100644 index 0000000..f4c9b8da --- /dev/null +++ b/media/blink/smoothness_helper_unittest.cc
@@ -0,0 +1,199 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/blink/smoothness_helper.h" + +#include "base/run_loop.h" +#include "media/blink/blink_platform_with_task_environment.h" +#include "media/learning/common/labelled_example.h" +#include "media/learning/common/learning_task_controller.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +using learning::FeatureValue; +using learning::FeatureVector; +using learning::LearningTask; +using learning::LearningTaskController; +using learning::ObservationCompletion; +using learning::TargetValue; + +using testing::_; +using testing::AnyNumber; +using testing::Eq; +using testing::Gt; +using testing::Lt; +using testing::ResultOf; +using testing::Return; + +// Helper for EXPECT_CALL argument matching on Optional<TargetValue>. Applies +// matcher |m| to the TargetValue as a double. For example: +// void Foo(base::Optional<TargetValue>); +// EXPECT_CALL(..., Foo(OPT_TARGET(Gt(0.9)))) will expect that the value of the +// Optional<TargetValue> passed to Foo() to be greather than 0.9 . +#define OPT_TARGET(m) \ + ResultOf([](const base::Optional<TargetValue>& v) { return (*v).value(); }, m) + +// Same as above, but expects an ObservationCompletion. +#define COMPLETION_TARGET(m) \ + ResultOf( \ + [](const ObservationCompletion& x) { return x.target_value.value(); }, \ + m) + +class SmoothnessHelperTest : public testing::Test { + class MockLearningTaskController : public LearningTaskController { + public: + MOCK_METHOD3(BeginObservation, + void(base::UnguessableToken id, + const FeatureVector& features, + const base::Optional<TargetValue>& default_target)); + + MOCK_METHOD2(CompleteObservation, + void(base::UnguessableToken id, + const ObservationCompletion& completion)); + + MOCK_METHOD1(CancelObservation, void(base::UnguessableToken id)); + + MOCK_METHOD2(UpdateDefaultTarget, + void(base::UnguessableToken id, + const base::Optional<TargetValue>& default_target)); + + MOCK_METHOD0(GetLearningTask, const LearningTask&()); + }; + + class MockClient : public SmoothnessHelper::Client { + public: + ~MockClient() override = default; + + MOCK_CONST_METHOD0(DecodedFrameCount, unsigned(void)); + MOCK_CONST_METHOD0(DroppedFrameCount, unsigned(void)); + }; + + public: + void SetUp() override { + auto ltc = std::make_unique<MockLearningTaskController>(); + ltc_ = ltc.get(); + features_.push_back(FeatureValue(123)); + helper_ = SmoothnessHelper::Create(std::move(ltc), features_, &client_); + segment_size_ = SmoothnessHelper::SegmentSizeForTesting(); + } + + // Helper for EXPECT_CALL. + base::Optional<TargetValue> Opt(double x) { + return base::Optional<TargetValue>(TargetValue(x)); + } + + void FastForwardBy(base::TimeDelta amount) { + BlinkPlatformWithTaskEnvironment::GetTaskEnvironment()->FastForwardBy( + amount); + } + + // Set the dropped / decoded totals that will be returned by the mock client. + void SetFrameCounters(int dropped, int decoded) { + ON_CALL(client_, DroppedFrameCount()).WillByDefault(Return(dropped)); + ON_CALL(client_, DecodedFrameCount()).WillByDefault(Return(decoded)); + } + + // Helper under test + std::unique_ptr<SmoothnessHelper> helper_; + + MockLearningTaskController* ltc_ = nullptr; + MockClient client_; + FeatureVector features_; + + base::TimeDelta segment_size_; +}; + +TEST_F(SmoothnessHelperTest, PauseWithoutPlayDoesNothing) { + EXPECT_CALL(*ltc_, BeginObservation(_, _, _)).Times(0); + helper_->NotifyPlayState(false); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(SmoothnessHelperTest, PlayThenImmediatePauseCancelsObservation) { + // If not enough time has elapsed, play then pause shouldn't record anything. + // Note that Begin then Cancel would be okay too, but it's hard to set + // expectations for either case. So, we just pick the one that it actually + // does in this case. + EXPECT_CALL(*ltc_, BeginObservation(_, _, _)).Times(0); + helper_->NotifyPlayState(true); + helper_->NotifyPlayState(false); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(SmoothnessHelperTest, PlayRecordsWorstSegment) { + // Record three segments, and see if it chooses the worst. + SetFrameCounters(0, 0); + helper_->NotifyPlayState(true); + base::RunLoop().RunUntilIdle(); + + // First segment has no dropped frames.. + EXPECT_CALL(*ltc_, BeginObservation(_, _, OPT_TARGET(Eq(0.0)))).Times(1); + SetFrameCounters(0, 1000); + FastForwardBy(segment_size_); + base::RunLoop().RunUntilIdle(); + + // Second segment has quite a lot of dropped frames. + EXPECT_CALL(*ltc_, UpdateDefaultTarget(_, OPT_TARGET(Gt(0.99)))).Times(1); + SetFrameCounters(999, 2000); + FastForwardBy(segment_size_); + base::RunLoop().RunUntilIdle(); + + // Third segment has no dropped frames, so the default shouldn't change. + EXPECT_CALL(*ltc_, UpdateDefaultTarget(_, OPT_TARGET(Gt(0.99)))).Times(1); + SetFrameCounters(999, 3000); + FastForwardBy(segment_size_); + base::RunLoop().RunUntilIdle(); + + EXPECT_CALL(*ltc_, CompleteObservation(_, COMPLETION_TARGET(Gt(0.99)))) + .Times(1); + helper_->NotifyPlayState(false); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(SmoothnessHelperTest, PlayIgnoresTrailingPartialSegments) { + helper_->NotifyPlayState(true); + base::RunLoop().RunUntilIdle(); + + // First segment has no dropped frames. + EXPECT_CALL(*ltc_, BeginObservation(_, _, OPT_TARGET(Eq(0.0)))).Times(1); + SetFrameCounters(0, 1000); + FastForwardBy(segment_size_); + base::RunLoop().RunUntilIdle(); + + // Second segment has a lot of dropped frames, but isn't a full segment. + SetFrameCounters(1000, 2000); + FastForwardBy(segment_size_ / 2); + base::RunLoop().RunUntilIdle(); + + // On completion, we the observation should have no dropped frames. + EXPECT_CALL(*ltc_, CompleteObservation(_, COMPLETION_TARGET(Lt(0.1)))) + .Times(1); + helper_->NotifyPlayState(false); + base::RunLoop().RunUntilIdle(); +} + +TEST_F(SmoothnessHelperTest, DestructionRecordsObservations) { + // Destroying |helper_| should not send any observation; the last default + // value should be used. + helper_->NotifyPlayState(true); + base::RunLoop().RunUntilIdle(); + + EXPECT_CALL(*ltc_, BeginObservation(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(*ltc_, UpdateDefaultTarget(_, _)).Times(AnyNumber()); + EXPECT_CALL(*ltc_, CancelObservation(_)).Times(0); + EXPECT_CALL(*ltc_, CompleteObservation(_, _)).Times(0); + + // Fast forward so that we're sure that there is something to record. + SetFrameCounters(0, 1000); + FastForwardBy(segment_size_); + SetFrameCounters(0, 2000); + FastForwardBy(segment_size_); + helper_.reset(); + + base::RunLoop().RunUntilIdle(); +} + +} // namespace media
diff --git a/media/blink/video_frame_compositor.h b/media/blink/video_frame_compositor.h index 876c27a..c8fe191 100644 --- a/media/blink/video_frame_compositor.h +++ b/media/blink/video_frame_compositor.h
@@ -105,7 +105,7 @@ // it was updated. In certain applications, one might need to periodically // call UpdateCurrentFrameIfStale on |task_runner_| to drive the updates. // Can be called from any thread. - scoped_refptr<VideoFrame> GetCurrentFrameOnAnyThread(); + virtual scoped_refptr<VideoFrame> GetCurrentFrameOnAnyThread(); // VideoRendererSink implementation. These methods must be called from the // same thread (typically the media thread). @@ -132,7 +132,7 @@ // Must be called on the compositor thread. virtual void SetOnNewProcessedFrameCallback(OnNewProcessedFrameCB cb); - void SetOnFramePresentedCallback(OnNewFramePresentedCB present_cb); + virtual void SetOnFramePresentedCallback(OnNewFramePresentedCB present_cb); // Updates the rotation information for frames given to |submitter_|. void UpdateRotation(VideoRotation rotation);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 8cd0a85..c6c8b77 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -369,13 +369,10 @@ always_enable_overlays_ = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kForceVideoOverlays); - if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo)) { - bool use_android_overlay = base::FeatureList::IsEnabled(kUseAndroidOverlay); - overlay_mode_ = use_android_overlay ? OverlayMode::kUseAndroidOverlay - : OverlayMode::kUseContentVideoView; - } else { + if (base::FeatureList::IsEnabled(kOverlayFullscreenVideo)) + overlay_mode_ = OverlayMode::kUseAndroidOverlay; + else overlay_mode_ = OverlayMode::kNoOverlays; - } delegate_id_ = delegate_->AddObserver(this); delegate_->SetIdle(delegate_id_, true); @@ -550,15 +547,6 @@ client_->OnPictureInPictureStateChange(); } -bool WebMediaPlayerImpl::SupportsOverlayFullscreenVideo() { -#if defined(OS_ANDROID) - return !using_media_player_renderer_ && - overlay_mode_ == OverlayMode::kUseContentVideoView; -#else - return false; -#endif -} - void WebMediaPlayerImpl::EnableOverlay() { overlay_enabled_ = true; if (request_routing_token_cb_ && @@ -579,9 +567,7 @@ void WebMediaPlayerImpl::DisableOverlay() { overlay_enabled_ = false; - if (overlay_mode_ == OverlayMode::kUseContentVideoView) { - surface_created_cb_.Cancel(); - } else if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) { + if (overlay_mode_ == OverlayMode::kUseAndroidOverlay) { token_available_cb_.Cancel(); overlay_routing_token_is_pending_ = false; overlay_routing_token_ = OverlayInfo::RoutingToken(); @@ -2782,6 +2768,9 @@ DCHECK(main_task_runner_->BelongsToCurrentThread()); TRACE_EVENT0("media", "WebMediaPlayerImpl::GetCurrentFrameFromCompositor"); + if (current_frame_override_) + return current_frame_override_; + // Can be null. scoped_refptr<VideoFrame> video_frame = compositor_->GetCurrentFrameOnAnyThread(); @@ -3286,6 +3275,28 @@ return bridge_->GetSurfaceId(); } +void WebMediaPlayerImpl::RequestAnimationFrame() { + vfc_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(&VideoFrameCompositor::SetOnFramePresentedCallback, + base::Unretained(compositor_.get()), + BindToCurrentLoop(base::BindOnce( + &WebMediaPlayerImpl::OnNewFramePresentedCallback, + weak_factory_.GetWeakPtr())))); +} + +void WebMediaPlayerImpl::OnNewFramePresentedCallback( + scoped_refptr<VideoFrame> presented_frame, + base::TimeTicks presentation_time, + base::TimeTicks expected_presentation_time, + uint32_t presentation_counter) { + current_frame_override_ = std::move(presented_frame); + client_->OnRequestAnimationFrame( + presentation_time, expected_presentation_time, presentation_counter, + *current_frame_override_); + current_frame_override_.reset(); +} + base::WeakPtr<blink::WebMediaPlayer> WebMediaPlayerImpl::AsWeakPtr() { return weak_this_; } @@ -3637,4 +3648,9 @@ return mb_data_source_ ? mb_data_source_->GetUrlAfterRedirects() : GURL(); } +void WebMediaPlayerImpl::SetCurrentFrameOverrideForTesting( + scoped_refptr<VideoFrame> current_frame_override) { + current_frame_override_ = current_frame_override; +} + } // namespace media
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 6e347ea..14ebb86c 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -219,7 +219,6 @@ blink::WebContentDecryptionModule* cdm, blink::WebContentDecryptionModuleResult result) override; - bool SupportsOverlayFullscreenVideo() override; void EnteredFullscreen() override; void ExitedFullscreen() override; void BecameDominantVisibleContent(bool is_dominant) override; @@ -281,6 +280,7 @@ int GetDelegateId() override; base::Optional<viz::SurfaceId> GetSurfaceId() override; GURL GetSrcAfterRedirects() override; + void RequestAnimationFrame() override; base::WeakPtr<blink::WebMediaPlayer> AsWeakPtr() override; @@ -607,11 +607,21 @@ // Switch to SurfaceLayer, either initially or from VideoLayer. void ActivateSurfaceLayerForVideo(); + // Called by |compositor_| upon presenting a frame, after + // RequestAnimationFrame() is called. + void OnNewFramePresentedCallback(scoped_refptr<VideoFrame> presented_frame, + base::TimeTicks presentation_time, + base::TimeTicks expected_presentation_time, + uint32_t presentation_counter); + // Notifies |mb_data_source_| of playback and rate changes which may increase // the amount of data the DataSource buffers. Does nothing prior to reaching // kReadyStateHaveEnoughData for the first time. void MaybeUpdateBufferSizesForPlayback(); + void SetCurrentFrameOverrideForTesting( + scoped_refptr<VideoFrame> current_frame_override); + blink::WebLocalFrame* const frame_; // The playback state last reported to |delegate_|, to avoid setting duplicate @@ -802,9 +812,6 @@ std::unique_ptr<RendererFactorySelector> renderer_factory_selector_; - // For canceling ongoing surface creation requests when exiting fullscreen. - base::CancelableCallback<void(int)> surface_created_cb_; - // For canceling AndroidOverlay routing token requests. base::CancelableCallback<void(const base::UnguessableToken&)> token_available_cb_; @@ -941,9 +948,6 @@ // All overlays are turned off. kNoOverlays, - // Use ContentVideoView for overlays. - kUseContentVideoView, - // Use AndroidOverlay for overlays. kUseAndroidOverlay, }; @@ -994,6 +998,10 @@ // Whether background video optimization is supported on current platform. bool is_background_video_track_optimization_supported_ = true; + // Valid while an active OnNewFramePresentedCallback() is in progress. + // Overrides the VideoFrame returned by GetCurrentFrameFromCompositor(). + scoped_refptr<VideoFrame> current_frame_override_; + base::CancelableOnceClosure have_enough_after_lazy_load_cb_; // State for simplified watch time reporting.
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc index 1fd9a16..af2eae8 100644 --- a/media/blink/webmediaplayer_impl_unittest.cc +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -152,6 +152,11 @@ MOCK_METHOD0(RequestPause, void()); MOCK_METHOD1(RequestMuted, void(bool)); MOCK_METHOD0(GetFeatures, Features(void)); + MOCK_METHOD4(OnRequestAnimationFrame, + void(base::TimeTicks, + base::TimeTicks, + uint32_t, + const media::VideoFrame&)); void set_was_always_muted(bool value) { was_always_muted_ = value; } @@ -290,9 +295,9 @@ ~MockVideoFrameCompositor() override = default; // MOCK_METHOD doesn't like OnceCallback. - void SetOnNewProcessedFrameCallback(OnNewProcessedFrameCB cb) override {} + MOCK_METHOD1(SetOnFramePresentedCallback, void(OnNewFramePresentedCB)); MOCK_METHOD1(SetIsPageVisible, void(bool)); - MOCK_METHOD0(GetCurrentFrameAndUpdateIfStale, scoped_refptr<VideoFrame>()); + MOCK_METHOD0(GetCurrentFrameOnAnyThread, scoped_refptr<VideoFrame>()); MOCK_METHOD4( EnableSubmission, void(const viz::SurfaceId&, base::TimeTicks, media::VideoRotation, bool)); @@ -617,6 +622,27 @@ return wmpi_->mb_data_source_->media_has_played(); } + scoped_refptr<VideoFrame> CreateFrame() { + gfx::Size size(8, 8); + return VideoFrame::CreateFrame(PIXEL_FORMAT_I420, size, gfx::Rect(size), + size, base::TimeDelta()); + } + + void RequestAnimationFrame() { wmpi_->RequestAnimationFrame(); } + + void OnNewFramePresentedCallback() { + wmpi_->OnNewFramePresentedCallback(CreateFrame(), base::TimeTicks::Now(), + base::TimeTicks::Now(), 1); + } + + scoped_refptr<VideoFrame> GetCurrentFrameFromCompositor() { + return wmpi_->GetCurrentFrameFromCompositor(); + } + + void SetCurrentFrameOverrideForTesting(scoped_refptr<VideoFrame> frame) { + wmpi_->SetCurrentFrameOverrideForTesting(frame); + } + enum class LoadType { kFullyBuffered, kStreaming }; void Load(std::string data_file, LoadType load_type = LoadType::kFullyBuffered) { @@ -1105,6 +1131,40 @@ EXPECT_FALSE(IsSuspended()); } +TEST_F(WebMediaPlayerImplTest, RequestAnimationFrame) { + InitializeWebMediaPlayerImpl(); + + EXPECT_CALL(*compositor_, SetOnFramePresentedCallback(_)); + RequestAnimationFrame(); +} + +TEST_F(WebMediaPlayerImplTest, OnNewFramePresentedCallback) { + InitializeWebMediaPlayerImpl(); + EXPECT_CALL(client_, OnRequestAnimationFrame(_, _, _, _)); + + OnNewFramePresentedCallback(); +} + +TEST_F(WebMediaPlayerImplTest, GetCurrentFrameFromCompositorOverride) { + scoped_refptr<VideoFrame> compositor_frame = CreateFrame(); + scoped_refptr<VideoFrame> override_frame = CreateFrame(); + + InitializeWebMediaPlayerImpl(); + + EXPECT_CALL(*compositor_, GetCurrentFrameOnAnyThread()) + .WillRepeatedly(Return(compositor_frame)); + + EXPECT_EQ(compositor_frame, GetCurrentFrameFromCompositor()); + + SetCurrentFrameOverrideForTesting(override_frame); + EXPECT_EQ(override_frame, GetCurrentFrameFromCompositor()); + + // After returning from OnNewFramePresentedCallback(), the overriding frame + // should be cleared. + OnNewFramePresentedCallback(); + EXPECT_EQ(compositor_frame, GetCurrentFrameFromCompositor()); +} + TEST_F(WebMediaPlayerImplTest, ComputePlayState_Constructed) { InitializeWebMediaPlayerImpl(); WebMediaPlayerImpl::PlayState state = ComputePlayState();
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc index b91cfc96e..b84f510 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.cc
@@ -14,6 +14,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" @@ -501,7 +502,7 @@ // 100 years after 01 January 1970 UTC. expiration = 3153600000.0; // 100 * 365 * 24 * 60 * 60; - if (!has_set_renewal_timer_) { + if (!has_set_timer_) { // Make sure the CDM can get time and sleep if necessary. constexpr auto kSleepDuration = base::TimeDelta::FromSeconds(1); auto start_time = base::Time::Now(); @@ -509,8 +510,7 @@ auto time_elapsed = base::Time::Now() - start_time; CHECK_GE(time_elapsed, kSleepDuration); - ScheduleNextRenewal(); - has_set_renewal_timer_ = true; + ScheduleNextTimer(); } // Also send an individualization request if never sent before. Only @@ -581,19 +581,27 @@ void ClearKeyCdm::TimerExpired(void* context) { DVLOG(1) << __func__; - DCHECK(has_set_renewal_timer_); + DCHECK(has_set_timer_); std::string renewal_message; - if (!next_renewal_message_.empty() && context == &next_renewal_message_[0]) { - renewal_message = next_renewal_message_; - } else { - renewal_message = "ERROR: Invalid timer context found!"; + + if (key_system_ == kExternalClearKeyMessageTypeTestKeySystem) { + if (!next_renewal_message_.empty() && + context == &next_renewal_message_[0]) { + renewal_message = next_renewal_message_; + } else { + renewal_message = "ERROR: Invalid timer context found!"; + } + + cdm_host_proxy_->OnSessionMessage( + last_session_id_.data(), last_session_id_.length(), + cdm::kLicenseRenewal, renewal_message.data(), renewal_message.length()); + } else if (key_system_ == kExternalClearKeyOutputProtectionTestKeySystem) { + // Check output protection again. + cdm_host_proxy_->QueryOutputProtectionStatus(); } - cdm_host_proxy_->OnSessionMessage( - last_session_id_.data(), last_session_id_.length(), cdm::kLicenseRenewal, - renewal_message.data(), renewal_message.length()); - - ScheduleNextRenewal(); + // Start the timer to schedule another timeout. + ScheduleNextTimer(); } static void CopyDecryptResults(media::Decryptor::Status* status_copy, @@ -770,8 +778,9 @@ delete this; } -void ClearKeyCdm::ScheduleNextRenewal() { - // Prepare the next renewal message and set timer. +void ClearKeyCdm::ScheduleNextTimer() { + // Prepare the next renewal message and set timer. Renewal message is only + // needed for the renewal test, and is ignored for other uses of the timer. std::ostringstream msg_stream; msg_stream << "Renewal from ClearKey CDM set at time " << base::Time::FromDoubleT(cdm_host_proxy_->GetCurrentWallTime()) @@ -779,6 +788,7 @@ next_renewal_message_ = msg_stream.str(); cdm_host_proxy_->SetTimer(timer_delay_ms_, &next_renewal_message_[0]); + has_set_timer_ = true; // Use a smaller timer delay at start-up to facilitate testing. Increase the // timer delay up to a limit to avoid message spam. @@ -838,27 +848,38 @@ cdm::QueryResult result, uint32_t link_mask, uint32_t output_protection_mask) { - DVLOG(1) << __func__; + DVLOG(1) << __func__ << " result:" << result << ", link_mask:" << link_mask + << ", output_protection_mask:" << output_protection_mask; if (!is_running_output_protection_test_) { NOTREACHED() << "OnQueryOutputProtectionStatus() called unexpectedly."; return; } - is_running_output_protection_test_ = false; - -// On Chrome OS, status query will fail on Linux Chrome OS build. So we ignore -// the query result. On all other platforms, status query should succeed. -// TODO(xhwang): Improve the check on Chrome OS builds. For example, use -// base::SysInfo::IsRunningOnChromeOS() to differentiate between real Chrome OS -// build and Linux Chrome OS build. -#if !defined(OS_CHROMEOS) - if (result != cdm::kQuerySucceeded || link_mask != 0) { - OnUnitTestComplete(false); - return; + // If the query fails or it succeeds and link mask contains kLinkTypeNetwork, + // send a 'keystatuschange' event with a key marked as output-restricted. + // As the JavaScript test doesn't check key IDs, use a dummy key ID. + // + // Note that QueryOutputProtectionStatus() is known to fail on Linux Chrome + // OS builds. + // + // Note that this does not modify any keys, so if the caller does not check + // the 'keystatuschange' event, nothing will happen as decoding will continue + // to work. + if (result != cdm::kQuerySucceeded || (link_mask & cdm::kLinkTypeNetwork)) { + // A session ID is needed, so use |last_session_id_|. However, if this is + // called before a session has been created, we have no session to send + // this to. Note that this only works with a single session, the same as + // renewal messages. + if (!last_session_id_.empty()) { + const uint8_t kDummyKeyId[] = {'d', 'u', 'm', 'm', 'y'}; + std::vector<cdm::KeyInformation> keys_vector = { + {kDummyKeyId, base::size(kDummyKeyId), cdm::kOutputRestricted, 0}}; + cdm_host_proxy_->OnSessionKeysChange( + last_session_id_.data(), last_session_id_.length(), false, + keys_vector.data(), keys_vector.size()); + } } -#endif - OnUnitTestComplete(true); } void ClearKeyCdm::OnStorageId(uint32_t version, @@ -972,6 +993,9 @@ DVLOG(1) << __func__; is_running_output_protection_test_ = true; cdm_host_proxy_->QueryOutputProtectionStatus(); + + // Also start the timer to run this periodically. + ScheduleNextTimer(); } void ClearKeyCdm::StartPlatformVerificationTest() {
diff --git a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h index 7e907c97..b33cd54 100644 --- a/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h +++ b/media/cdm/library_cdm/clear_key_cdm/clear_key_cdm.h
@@ -138,7 +138,7 @@ void OnUpdateSuccess(uint32_t promise_id, const std::string& session_id); // Prepares next renewal message and sets a timer for it. - void ScheduleNextRenewal(); + void ScheduleNextTimer(); // Decrypts the |encrypted_buffer| and puts the result in |decrypted_buffer|. // Returns cdm::kSuccess if decryption succeeded. The decrypted result is @@ -158,6 +158,7 @@ void OnFileIOTestComplete(bool success); void StartOutputProtectionTest(); + void StartPlatformVerificationTest(); void ReportVerifyCdmHostTestResult(); void StartStorageIdTest(); @@ -182,9 +183,9 @@ // Timer delay in milliseconds for the next cdm_host_proxy_->SetTimer() call. int64_t timer_delay_ms_ = kInitialTimerDelayMs; - // Indicates whether a renewal timer has been set to prevent multiple timers - // from running. - bool has_set_renewal_timer_ = false; + // Indicates whether a timer has been set to prevent multiple timers from + // running. + bool has_set_timer_ = false; bool has_sent_individualization_request_ = false;
diff --git a/media/test/data/eme_and_get_display_media.html b/media/test/data/eme_and_get_display_media.html new file mode 100644 index 0000000..34dad7d --- /dev/null +++ b/media/test/data/eme_and_get_display_media.html
@@ -0,0 +1,126 @@ +<!DOCTYPE html> +<title>Test EME and getDisplayMedia()</title> +<div id="logs"></div> +<script src='eme_player_js/app_loader.js' type='text/javascript'></script> +<script type='text/javascript'> + // This test only checks for 'createMediaRecorderBeforeMediaKeys' in the URL + // parameters. If it is there, then the MediaRecorder is setup and started + // before MediaKeys is created. If not there, then the MediaRecorder is only + // created after MediaKeys is created. + var createMediaRecorderBeforeMediaKeys = + (window.location.href.indexOf('createMediaRecorderBeforeMediaKeys') > -1); + + // Use the default KEY_ID and KEY as specified in eme_player_js/globals.js. + const keyId = KEY_ID; + const key = KEY; + + // Returns a MediaKeys object that is already setup with a single session + // containing the key needed to play a typical test file. + async function setUpEME() { + // This test doesn't play any media, so use a simple + // MediaKeySystemConfiguration that should be supported by + // all platforms where External ClearKey CDM is supported. + const config = [{ + initDataTypes : [ 'keyids' ], + videoCapabilities: [{contentType: 'video/webm; codecs="vp8"'}], + }]; + var access = await navigator.requestMediaKeySystemAccess( + OUTPUT_PROTECTION_TEST_KEYSYSTEM, config); + var mediaKeys = await access.createMediaKeys(); + Utils.timeLog('Creating session'); + var mediaKeySession = mediaKeys.createSession(); + + // Handle 'keystatuseschange' events. There will be one after update() is + // called, as well as a later one when output protection detects the media + // recording. As this is testing output protection, if it reports + // 'output-restricted', then the test is a success. If not, simply continue + // on. + mediaKeySession.addEventListener('keystatuseschange', function(event) { + var result = []; + for (let item of event.target.keyStatuses) { + result.push(`{kid:${ + Utils.getHexString( + Utils.convertToUint8Array(item[0]))},status:${item[1]}}`); + } + Utils.timeLog('Event: keystatuseschange ' + result.join(',')); + for (let item of event.target.keyStatuses) { + if (item[1] == 'output-restricted') { + Utils.setResultInTitle(UNIT_TEST_SUCCESS); + } + } + }); + + // Register for the 'message' event before it happens. Although the event + // shouldn't be generated until after the generateRequest() promise is + // resolved, the handlers may be queued before the JavaScript code runs + // (and thus be lost if an event handler is not registered). + const waitForMessagePromise = Utils.waitForEvent( + mediaKeySession, 'message', function(event, resolve, reject) { + // When the 'message' event happens, we know the key to be + // used, so simply call update() and then call |resolve| or + // |reject| as appropriate. + Utils.timeLog('Calling update()'); + const mediaKeySession = event.target; + const jwkSet = Utils.createJWKData(keyId, key); + mediaKeySession.update(jwkSet).then(resolve, reject); + }); + + // As this is using 'webm' initDataType, the data to generateRequest() + // is simply the key ID. + Utils.timeLog('Calling generateRequest()'); + const generateRequestPromise = mediaKeySession.generateRequest( + 'webm', Utils.convertToUint8Array(keyId)); + + await Promise.all([generateRequestPromise, waitForMessagePromise]); + return mediaKeys; + } + + // Return a MediaRecorder object setup to record something (browsertests set + // a flag to by default capture the screen, if run manually the user will + // have to select something). + async function setUpRecorder() { + Utils.timeLog( + 'Creating MediaRecorder on navigator.mediaDevices.getDisplayMedia()'); + captureStream = await navigator.mediaDevices.getDisplayMedia({}); + var recorder = new MediaRecorder(captureStream, {}); + recorder.addEventListener('start', function() { + Utils.timeLog('Event: MediaRecorder::start'); + }); + recorder.start(); + return recorder; + } + + async function sleep(timeout) { + return new Promise(function(resolve) { + Utils.timeLog('Sleeping for ' + timeout + 'ms'); + window.setTimeout(function() { + resolve(); + }, timeout); + }); + } + + async function runTest() { + Utils.resetTitleChange(); + + if (createMediaRecorderBeforeMediaKeys) { + // Create the MediaRecorder before setting up EME. + await setUpRecorder(); + } + + var mediaKeys = await setUpEME(); + + if (!createMediaRecorderBeforeMediaKeys) { + // Create the MediaRecorder after a delay of 1/2 second. + await sleep(500); + await setUpRecorder(); + } + } + + try { + runTest(); + } catch (error) { + Utils.timeLog(error); + Utils.failTest('Failed test.'); + } +</script> +</html>
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn index 069a4bfe..2c44d3b 100644 --- a/mojo/public/cpp/bindings/BUILD.gn +++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -153,6 +153,8 @@ "lib/control_message_handler.h", "lib/control_message_proxy.cc", "lib/control_message_proxy.h", + "lib/generated_code_util.cc", + "lib/generated_code_util.h", "lib/interface_endpoint_client.cc", "lib/interface_ptr_state.cc", "lib/interface_ptr_state.h",
diff --git a/mojo/public/cpp/bindings/lib/generated_code_util.cc b/mojo/public/cpp/bindings/lib/generated_code_util.cc new file mode 100644 index 0000000..7851d0f6 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/generated_code_util.cc
@@ -0,0 +1,123 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/public/cpp/bindings/lib/generated_code_util.h" + +#include <cstring> + +#include "mojo/public/cpp/bindings/lib/control_message_handler.h" +#include "mojo/public/cpp/bindings/lib/validation_context.h" +#include "mojo/public/cpp/bindings/lib/validation_util.h" +#include "mojo/public/cpp/bindings/message.h" + +namespace mojo { +namespace internal { + +namespace { + +GenericValidationInfo FindGenericValidationInfo( + uint32_t name, + base::span<const std::pair<uint32_t, GenericValidationInfo>> info) { + for (const auto& pair : info) { + if (pair.first == name) + return pair.second; + } + return {nullptr, nullptr}; +} + +GenericValidationInfo FindGenericValidationInfo( + uint32_t name, + base::span<const GenericValidationInfo> info) { + if (name >= info.size()) + return {nullptr, nullptr}; + return info[name]; +} + +template <typename T> +bool ValidateRequestGenericT(Message* message, + const char* class_name, + base::span<const T> info) { + if (!message->is_serialized() || + ControlMessageHandler::IsControlMessage(message)) { + return true; + } + + ValidationContext validation_context(message, class_name, + ValidationContext::kRequestValidator); + + auto entry = FindGenericValidationInfo(message->header()->name, info); + if (!entry.request_validator) { + ReportValidationError(&validation_context, + VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); + return false; + } + + const bool message_is_request = + entry.response_validator ? ValidateMessageIsRequestExpectingResponse( + message, &validation_context) + : ValidateMessageIsRequestWithoutResponse( + message, &validation_context); + if (!message_is_request) + return false; + + return entry.request_validator(message->payload(), &validation_context); +} + +template <typename T> +bool ValidateResponseGenericT(Message* message, + const char* class_name, + base::span<const T> info) { + if (!message->is_serialized() || + ControlMessageHandler::IsControlMessage(message)) { + return true; + } + + ValidationContext validation_context(message, class_name, + ValidationContext::kResponseValidator); + + if (!ValidateMessageIsResponse(message, &validation_context)) + return false; + + auto entry = FindGenericValidationInfo(message->header()->name, info); + if (!entry.response_validator) { + ReportValidationError(&validation_context, + VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); + return false; + } + + return entry.response_validator(message->payload(), &validation_context); +} + +} // namespace + +bool ValidateRequestGeneric( + Message* message, + const char* class_name, + base::span<const std::pair<uint32_t, GenericValidationInfo>> info) { + return ValidateRequestGenericT(message, class_name, info); +} + +bool ValidateRequestGenericPacked( + Message* message, + const char* class_name, + base::span<const GenericValidationInfo> info) { + return ValidateRequestGenericT(message, class_name, info); +} + +bool ValidateResponseGeneric( + Message* message, + const char* class_name, + base::span<const std::pair<uint32_t, GenericValidationInfo>> info) { + return ValidateResponseGenericT(message, class_name, info); +} + +bool ValidateResponseGenericPacked( + Message* message, + const char* class_name, + base::span<const GenericValidationInfo> info) { + return ValidateResponseGenericT(message, class_name, info); +} + +} // namespace internal +} // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/generated_code_util.h b/mojo/public/cpp/bindings/lib/generated_code_util.h new file mode 100644 index 0000000..46d68b74 --- /dev/null +++ b/mojo/public/cpp/bindings/lib/generated_code_util.h
@@ -0,0 +1,62 @@ +// 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. + +#ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_GENERATED_CODE_UTIL_H_ +#define MOJO_PUBLIC_CPP_BINDINGS_LIB_GENERATED_CODE_UTIL_H_ + +#include <utility> +#include "base/component_export.h" +#include "base/containers/span.h" + +namespace mojo { + +class Message; + +namespace internal { + +class ValidationContext; + +struct GenericValidationInfo { + // Non-null, unless this corresponds to a non-existent method. + bool (*request_validator)(const void* data, ValidationContext*); + + // Non-null, unless this corresponds to a method that does not expect a + // response. + bool (*response_validator)(const void* data, ValidationContext*); +}; + +// Provides a generic implementation of the Mojo IPC request validation, +// allowing callers to do a compact tail call in generated code. +COMPONENT_EXPORT(MOJO_CPP_BINDINGS) +bool ValidateRequestGeneric( + Message* message, + const char* class_name, + base::span<const std::pair<uint32_t, GenericValidationInfo>>); + +// As above, but assumes that the ordinals (names) are packed such that a +// constant-time indexed table access is sufficient. +COMPONENT_EXPORT(MOJO_CPP_BINDINGS) +bool ValidateRequestGenericPacked(Message* message, + const char* class_name, + base::span<const GenericValidationInfo>); + +// Provides a generic implementation of the Mojo IPC response validation, +// allowing callers to do a compact tail call in generated code. +COMPONENT_EXPORT(MOJO_CPP_BINDINGS) +bool ValidateResponseGeneric( + Message* message, + const char* class_name, + base::span<const std::pair<uint32_t, GenericValidationInfo>>); + +// As above, but assumes that the ordinals (names) are packed such that a +// constant-time indexed table access is sufficient. +COMPONENT_EXPORT(MOJO_CPP_BINDINGS) +bool ValidateResponseGenericPacked(Message* message, + const char* class_name, + base::span<const GenericValidationInfo>); + +} // namespace internal +} // namespace mojo + +#endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_GENERATED_CODE_UTIL_H_
diff --git a/mojo/public/cpp/bindings/lib/validation_context.cc b/mojo/public/cpp/bindings/lib/validation_context.cc index d8dc437..2130837 100644 --- a/mojo/public/cpp/bindings/lib/validation_context.cc +++ b/mojo/public/cpp/bindings/lib/validation_context.cc
@@ -16,9 +16,11 @@ size_t num_associated_endpoint_handles, Message* message, const char* description, - int stack_depth) + int stack_depth, + ValidatorType validator_type) : message_(message), description_(description), + validator_type_(validator_type), data_begin_(reinterpret_cast<uintptr_t>(data)), data_end_(data_begin_ + data_num_bytes), handle_begin_(0), @@ -44,16 +46,33 @@ } } -ValidationContext::ValidationContext(Message* message, const char* description) +ValidationContext::ValidationContext(Message* message, + const char* description, + ValidatorType validator_type) : ValidationContext(message->payload(), message->payload_num_bytes(), message->handles()->size(), message->payload_num_interface_ids(), message, - description) {} + description, + 0, + validator_type) {} ValidationContext::~ValidationContext() { } +std::string ValidationContext::GetFullDescription() const { + std::string full_description(description_); + switch (validator_type_) { + case kUnspecifiedValidator: + case kRequestValidator: + break; + case kResponseValidator: + full_description += " response"; + break; + } + return full_description; +} + } // namespace internal } // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/validation_context.h b/mojo/public/cpp/bindings/lib/validation_context.h index 9d24b4e..8989b49 100644 --- a/mojo/public/cpp/bindings/lib/validation_context.h +++ b/mojo/public/cpp/bindings/lib/validation_context.h
@@ -7,6 +7,7 @@ #include <stddef.h> #include <stdint.h> +#include <string> #include "base/compiler_specific.h" #include "base/component_export.h" @@ -25,6 +26,12 @@ // indices in the payload of incoming messages. class COMPONENT_EXPORT(MOJO_CPP_BINDINGS_BASE) ValidationContext { public: + enum ValidatorType { + kUnspecifiedValidator, + kRequestValidator, + kResponseValidator + }; + // [data, data + data_num_bytes) specifies the initial valid memory range. // [0, num_handles) specifies the initial valid range of handle indices. // [0, num_associated_endpoint_handles) specifies the initial valid range of @@ -40,11 +47,14 @@ size_t num_associated_endpoint_handles, Message* message = nullptr, const char* description = "", - int stack_depth = 0); + int stack_depth = 0, + ValidatorType validator_type = kUnspecifiedValidator); // As above, but infers most of the parameters from the Message payload. // Used heavily in generated code and so affects binary size. - ValidationContext(Message* message, const char* description); + ValidationContext(Message* message, + const char* description, + ValidatorType validator_type); ~ValidationContext(); @@ -139,6 +149,7 @@ Message* message() const { return message_; } const char* description() const { return description_; } + std::string GetFullDescription() const; private: bool InternalIsValidRange(uintptr_t begin, uintptr_t end) const { @@ -147,6 +158,7 @@ Message* const message_; const char* const description_; + const ValidatorType validator_type_; // [data_begin_, data_end_) is the valid memory range. uintptr_t data_begin_;
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc index 8634d483..472e8661 100644 --- a/mojo/public/cpp/bindings/lib/validation_errors.cc +++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -77,17 +77,19 @@ << " (" << description << ")"; } if (context->message()) { - context->message()->NotifyBadMessage(base::StringPrintf( - "Validation failed for %s [%s (%s)]", context->description(), - ValidationErrorToString(error), description)); + context->message()->NotifyBadMessage( + base::StringPrintf("Validation failed for %s [%s (%s)]", + context->GetFullDescription().c_str(), + ValidationErrorToString(error), description)); } } else { if (!g_suppress_logging) LOG(ERROR) << "Invalid message: " << ValidationErrorToString(error); if (context->message()) { - context->message()->NotifyBadMessage(base::StringPrintf( - "Validation failed for %s [%s]", context->description(), - ValidationErrorToString(error))); + context->message()->NotifyBadMessage( + base::StringPrintf("Validation failed for %s [%s]", + context->GetFullDescription().c_str(), + ValidationErrorToString(error))); } } }
diff --git a/mojo/public/js/BUILD.gn b/mojo/public/js/BUILD.gn index 9054cb5..bf728bc 100644 --- a/mojo/public/js/BUILD.gn +++ b/mojo/public/js/BUILD.gn
@@ -85,6 +85,7 @@ "language_out=ECMASCRIPT_2015", "generate_exports", "export_local_property_definitions", + "isolation_mode=IIFE", ] } } else {
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni index 31d10363..0dff1689 100644 --- a/mojo/public/tools/bindings/blink_bindings_configuration.gni +++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -10,6 +10,7 @@ "//cc/typemaps.gni", "//device/gamepad/public/cpp/typemaps.gni", "//mojo/public/cpp/bindings/tests/blink_typemaps.gni", + "//skia/public/mojom/typemaps.gni", "//third_party/blink/renderer/platform/mojo/blink_typemaps.gni", "//third_party/blink/public/blink_typemaps.gni", ]
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl index e8344eb..f232de6 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -3,7 +3,9 @@ {%- set class_name = interface.name %} {%- set proxy_name = interface.name ~ "Proxy" %} -{%- set namespace_as_string = "%s"|format(namespace|replace(".","::")) %} +{%- set namespace_as_string = "%s"|format(module_namespace|replace(".","::")) %} +{%- set namespace_as_string_with_variant = namespace_as_string ~ ("::" ~ variant if variant) %} +{%- set qualified_class_name = ("::" ~ namespace_as_string_with_variant if namespace_as_string_with_variant) ~ "::" ~ class_name %} {%- macro alloc_params(struct, params, message, method_number, is_response) %} mojo::internal::SerializationContext serialization_context; @@ -518,82 +520,58 @@ return false; } +{% if interface.methods and (interface | has_packed_method_ordinals) %} +static const mojo::internal::GenericValidationInfo k{{class_name}}ValidationInfo[] = { +{%- for i in range(interface.methods | map(attribute='ordinal') | max + 1) -%} +{%- set method = (interface.methods | selectattr('ordinal', 'equalto', i) | list)[0] %} +{%- if method %} + {&internal::{{class_name}}_{{method.name}}_Params_Data::Validate, +{%- if method.response_parameters != None %} + &internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate}, +{%- else %} + nullptr /* no response */}, +{%- endif %} +{%- else %} + {nullptr, nullptr}, // nonexistent +{%- endif %} +{%- endfor %} +}; +{%- elif interface.methods %} +static const std::pair<uint32_t, mojo::internal::GenericValidationInfo> k{{class_name}}ValidationInfo[] = { +{%- for method in interface.methods %} + {internal::k{{class_name}}_{{method.name}}_Name, + {&internal::{{class_name}}_{{method.name}}_Params_Data::Validate, +{%- if method.response_parameters != None %} + &internal::{{class_name}}_{{method.name}}_ResponseParams_Data::Validate}}, +{%- else %} + nullptr /* no response */}}, +{%- endif %} +{%- endfor %} +}; +{%- endif %} + {#--- Request validator definitions #} bool {{class_name}}RequestValidator::Accept(mojo::Message* message) { - if (!message->is_serialized() || - mojo::internal::ControlMessageHandler::IsControlMessage(message)) { - return true; - } - - mojo::internal::ValidationContext validation_context( - message, "{{class_name}} RequestValidator"); - - switch (message->header()->name) { -{%- for method in interface.methods %} - case internal::k{{class_name}}_{{method.name}}_Name: { -{%- if method.response_parameters != None %} - if (!mojo::internal::ValidateMessageIsRequestExpectingResponse( - message, &validation_context)) { - return false; - } -{%- else %} - if (!mojo::internal::ValidateMessageIsRequestWithoutResponse( - message, &validation_context)) { - return false; - } -{%- endif %} - if (!mojo::internal::ValidateMessagePayload< - internal::{{class_name}}_{{method.name}}_Params_Data>( - message, &validation_context)) { - return false; - } - return true; - } -{%- endfor %} - default: - break; - } - - // Unrecognized message. - ReportValidationError( - &validation_context, - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); - return false; + {#- Not simply Name_ because there is a mojom interface called MessageReceiver #} + const char* name = {{qualified_class_name}}::Name_; +{%- if not interface.methods %} + return mojo::internal::ValidateRequestGeneric(message, name, {}); +{%- elif interface | has_packed_method_ordinals %} + return mojo::internal::ValidateRequestGenericPacked(message, name, k{{class_name}}ValidationInfo); +{%- else %} + return mojo::internal::ValidateRequestGeneric(message, name, k{{class_name}}ValidationInfo); +{%- endif %} } {#--- Response validator definitions #} {% if interface|has_callbacks %} bool {{class_name}}ResponseValidator::Accept(mojo::Message* message) { - if (!message->is_serialized() || - mojo::internal::ControlMessageHandler::IsControlMessage(message)) { - return true; - } - - mojo::internal::ValidationContext validation_context( - message, "{{class_name}} ResponseValidator"); - - if (!mojo::internal::ValidateMessageIsResponse(message, &validation_context)) - return false; - switch (message->header()->name) { -{%- for method in interface.methods if method.response_parameters != None %} - case internal::k{{class_name}}_{{method.name}}_Name: { - if (!mojo::internal::ValidateMessagePayload< - internal::{{class_name}}_{{method.name}}_ResponseParams_Data>( - message, &validation_context)) { - return false; - } - return true; - } -{%- endfor %} - default: - break; - } - - // Unrecognized message. - ReportValidationError( - &validation_context, - mojo::internal::VALIDATION_ERROR_MESSAGE_HEADER_UNKNOWN_METHOD); - return false; + const char* name = {{qualified_class_name}}::Name_; +{%- if interface | has_packed_method_ordinals %} + return mojo::internal::ValidateResponseGenericPacked(message, name, k{{class_name}}ValidationInfo); +{%- else %} + return mojo::internal::ValidateResponseGeneric(message, name, k{{class_name}}ValidationInfo); +{% endif %} } {%- endif -%}
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl index 89aed47..6a10b73 100644 --- a/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl +++ b/mojo/public/tools/bindings/generators/cpp_templates/module.cc.tmpl
@@ -32,6 +32,7 @@ #include "base/logging.h" #include "base/run_loop.h" #include "base/task/common/task_annotator.h" +#include "mojo/public/cpp/bindings/lib/generated_code_util.h" #include "mojo/public/cpp/bindings/lib/message_internal.h" #include "mojo/public/cpp/bindings/lib/serialization_util.h" #include "mojo/public/cpp/bindings/lib/unserialized_message_context.h"
diff --git a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py index e9c3e624b..4009887 100644 --- a/mojo/public/tools/bindings/generators/mojom_cpp_generator.py +++ b/mojo/public/tools/bindings/generators/mojom_cpp_generator.py
@@ -177,6 +177,13 @@ for field in union.fields) +def HasPackedMethodOrdinals(interface): + """Returns whether all method ordinals are packed such that indexing into a + table would be efficient.""" + max_ordinal = len(interface.methods) * 2 + return all(method.ordinal < max_ordinal for method in interface.methods) + + class StructConstructor(object): """Represents a constructor for a generated struct. @@ -367,6 +374,7 @@ "get_pad": pack.GetPad, "get_qualified_name_for_kind": self._GetQualifiedNameForKind, "has_callbacks": mojom.HasCallbacks, + "has_packed_method_ordinals": HasPackedMethodOrdinals, "has_sync_methods": mojom.HasSyncMethods, "method_supports_lazy_serialization": self._MethodSupportsLazySerialization,
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni index 35c05bf..9344bdcd 100644 --- a/mojo/public/tools/bindings/mojom.gni +++ b/mojo/public/tools/bindings/mojom.gni
@@ -940,6 +940,12 @@ if (enable_kythe_annotations) { args += [ "--enable_kythe_annotations" ] } + + if (!defined(invoker.scramble_message_ids) || + invoker.scramble_message_ids) { + inputs += message_scrambling_inputs + args += message_scrambling_args + } } }
diff --git a/net/BUILD.gn b/net/BUILD.gn index 838971a..016a2ab 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -6211,6 +6211,9 @@ "//net", ] dict = "data/fuzzer_dictionaries/net_data_url_fuzzer.dict" + + # IsTokenChar() and ToLowerASCII() are surprisingly slow in instrumented builds. + libfuzzer_options = [ "max_len=100000" ] } fuzzer_test("net_mime_sniffer_fuzzer") {
diff --git a/net/base/hex_utils.cc b/net/base/hex_utils.cc index aec608b..03a3c2a 100644 --- a/net/base/hex_utils.cc +++ b/net/base/hex_utils.cc
@@ -5,22 +5,11 @@ #include "net/base/hex_utils.h" #include <algorithm> -#include <cstdint> -#include <vector> -#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" namespace net { -std::string HexDecode(base::StringPiece input) { - std::vector<uint8_t> output; - std::string result; - if (base::HexStringToBytes(input, &output)) - result.assign(reinterpret_cast<const char*>(output.data()), output.size()); - return result; -} - std::string HexDump(base::StringPiece input) { const int kBytesPerLine = 16; // Maximum bytes dumped per line. int offset = 0;
diff --git a/net/base/hex_utils.h b/net/base/hex_utils.h index 3343d6d..b09be9b8 100644 --- a/net/base/hex_utils.h +++ b/net/base/hex_utils.h
@@ -12,11 +12,6 @@ namespace net { -// Return a std::string of binary data represented by the hex string |input|. -// For example, HexDecode("48656c6c6f20776f726c6421") == "Hello world!" -// This is the inverse function of base::HexEncode(). -NET_EXPORT_PRIVATE std::string HexDecode(base::StringPiece input); - // Return a std::string containing hex and ASCII representations of the binary // buffer |input|, with offsets at the beginning of each line, in the style of // hexdump. Non-printable characters will be shown as '.' in the ASCII output.
diff --git a/net/base/hex_utils_test.cc b/net/base/hex_utils_test.cc index bdf27526..a812be1 100644 --- a/net/base/hex_utils_test.cc +++ b/net/base/hex_utils_test.cc
@@ -9,13 +9,6 @@ namespace test { -TEST(HexUtilsTest, HexDecode) { - EXPECT_EQ("", HexDecode("")); - EXPECT_EQ("a", HexDecode("61")); - // Mixed case input. - EXPECT_EQ("Hello world!", HexDecode("48656c6C6F20776f726C6421")); -} - TEST(HexUtilsTest, HexDump) { EXPECT_EQ("", HexDump("")); EXPECT_EQ("0x0000: 4865 6c6c 6f20 776f 726c 6421 Hello.world!\n", @@ -26,11 +19,11 @@ HexDump("PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n")); // Verify that 0x21 and 0x7e are printable, 0x20 and 0x7f are not. EXPECT_EQ("0x0000: 2021 7e7f .!~.\n", - HexDump(HexDecode("20217e7f"))); + HexDump("\x20\x21\x7e\x7f")); // Verify that values above numeric_limits<unsigned char>::max() are cast // properly on platforms where char is unsigned. EXPECT_EQ("0x0000: 90aa ff ...\n", - HexDump(HexDecode("90aaff"))); + HexDump("\x90\xaa\xff")); } } // namespace test
diff --git a/net/cert/ct_log_verifier_unittest.cc b/net/cert/ct_log_verifier_unittest.cc index dcdc6ced..4bbc080a 100644 --- a/net/cert/ct_log_verifier_unittest.cc +++ b/net/cert/ct_log_verifier_unittest.cc
@@ -155,10 +155,9 @@ // Decodes a hexadecimal string into the binary data it represents. std::string HexToBytes(const std::string& hex_data) { - std::vector<uint8_t> output; std::string result; - if (base::HexStringToBytes(hex_data, &output)) - result.assign(output.begin(), output.end()); + if (!base::HexStringToString(hex_data, &result)) + result.clear(); return result; }
diff --git a/net/cert/x509_certificate_unittest.cc b/net/cert/x509_certificate_unittest.cc index b378df5..f521740c 100644 --- a/net/cert/x509_certificate_unittest.cc +++ b/net/cert/x509_certificate_unittest.cc
@@ -1337,11 +1337,10 @@ ASSERT_NE(0U, addr_ascii.length()); if (addr_ascii[0] == 'x') { // Hex encoded address addr_ascii.erase(0, 1); - std::vector<uint8_t> bytes; - EXPECT_TRUE(base::HexStringToBytes(addr_ascii, &bytes)) + std::string bytes; + EXPECT_TRUE(base::HexStringToString(addr_ascii, &bytes)) << "Could not parse hex address " << addr_ascii << " i = " << i; - ip_addressses.push_back( - std::string(reinterpret_cast<char*>(bytes.data()), bytes.size())); + ip_addressses.push_back(std::move(bytes)); ASSERT_EQ(16U, ip_addressses.back().size()) << i; } else { // Decimal groups std::vector<std::string> decimals_ascii = base::SplitString(
diff --git a/net/http2/platform/impl/http2_string_utils_impl.h b/net/http2/platform/impl/http2_string_utils_impl.h index 3bd8be7..4dd894b 100644 --- a/net/http2/platform/impl/http2_string_utils_impl.h +++ b/net/http2/platform/impl/http2_string_utils_impl.h
@@ -41,7 +41,10 @@ } inline std::string Http2HexDecodeImpl(Http2StringPiece data) { - return net::HexDecode(data); + std::string result; + if (!base::HexStringToString(data, &result)) + result.clear(); + return result; } inline std::string Http2HexDumpImpl(Http2StringPiece data) {
diff --git a/net/quic/platform/impl/quic_text_utils_impl.h b/net/quic/platform/impl/quic_text_utils_impl.h index d9feafc..96b48214 100644 --- a/net/quic/platform/impl/quic_text_utils_impl.h +++ b/net/quic/platform/impl/quic_text_utils_impl.h
@@ -87,9 +87,12 @@ } // Converts |data| from a hexadecimal ASCII string to a binary string - // that is |data.length()/2| bytes long. + // that is |data.length()/2| bytes long. On failure returns empty string. static std::string HexDecode(QuicStringPiece data) { - return net::HexDecode(data); + std::string result; + if (!base::HexStringToString(data, &result)) + result.clear(); + return result; } // Base64 encodes with no padding |data_len| bytes of |data| into |output|.
diff --git a/net/quic/quic_chromium_packet_reader.cc b/net/quic/quic_chromium_packet_reader.cc index e8f5f78..fd661b1b 100644 --- a/net/quic/quic_chromium_packet_reader.cc +++ b/net/quic/quic_chromium_packet_reader.cc
@@ -125,8 +125,12 @@ socket_->GetLocalAddress(&local_address_); socket_->GetPeerAddress(&peer_address_); } + auto self = weak_factory_.GetWeakPtr(); + // Notifies the visitor that |this| reader gets a new packet, which may delete + // |this| if |this| is a connectivity probing reader. return visitor_->OnPacket(packet, ToQuicSocketAddress(local_address_), - ToQuicSocketAddress(peer_address_)); + ToQuicSocketAddress(peer_address_)) && + self; } void QuicChromiumPacketReader::OnReadComplete(int result) {
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 2f78757..a618289 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -4352,6 +4352,177 @@ EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); } +// Regression test for https://crbug.com/1014092. +TEST_P(QuicStreamFactoryTest, MultiplePortMigrationsExceedsMaxLimit) { + test_params_.quic_params.allow_port_migration = true; + socket_factory_.reset(new TestMigrationSocketFactory); + Initialize(); + + ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + crypto_client_stream_factory_.AddProofVerifyDetails(&verify_details); + + // Using a testing task runner so that we can control time. + auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>(); + QuicStreamFactoryPeer::SetTaskRunner(factory_.get(), task_runner.get()); + + int packet_number = 1; + MockQuicData quic_data1(version_); + quic_data1.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // Hanging Read. + if (VersionUsesHttp3(version_.transport_version)) { + quic_data1.AddWrite(SYNCHRONOUS, + ConstructInitialSettingsPacket(packet_number++)); + } + quic_data1.AddWrite( + SYNCHRONOUS, + ConstructGetRequestPacket(packet_number++, + GetNthClientInitiatedBidirectionalStreamId(0), + true, true)); + quic_data1.AddSocketDataToFactory(socket_factory_.get()); + + // Create request and QuicHttpStream. + QuicStreamRequest request(factory_.get()); + EXPECT_EQ( + ERR_IO_PENDING, + request.Request( + host_port_pair_, version_, privacy_mode_, DEFAULT_PRIORITY, + SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */, + /*cert_verify_flags=*/0, url_, net_log_, &net_error_details_, + failed_on_default_network_callback_, callback_.callback())); + EXPECT_THAT(callback_.WaitForResult(), IsOk()); + std::unique_ptr<HttpStream> stream = CreateStream(&request); + EXPECT_TRUE(stream.get()); + + // Cause QUIC stream to be created. + HttpRequestInfo request_info; + request_info.method = "GET"; + request_info.url = url_; + request_info.traffic_annotation = + MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS); + EXPECT_EQ(OK, stream->InitializeStream(&request_info, true, DEFAULT_PRIORITY, + net_log_, CompletionOnceCallback())); + + // Ensure that session is alive and active. + QuicChromiumClientSession* session = GetActiveSession(host_port_pair_); + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + + // Send GET request on stream. + HttpResponseInfo response; + HttpRequestHeaders request_headers; + EXPECT_EQ(OK, stream->SendRequest(request_headers, &response, + callback_.callback())); + + int server_packet_num = 1; + base::TimeDelta next_task_delay; + // Perform 4 round of successful migration, and the 5th round will + // cancel after successful probing due to hitting the limit. + for (int i = 0; i <= 4; i++) { + // Set up a different socket data provider that is used for + // probing and migration. + MockQuicData quic_data2(version_); + // Connectivity probe to be sent on the new path. + quic_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakeConnectivityProbingPacket( + packet_number, packet_number == 2)); + packet_number++; + quic_data2.AddRead(ASYNC, ERR_IO_PENDING); // Pause + // Connectivity probe to receive from the server. + quic_data2.AddRead(ASYNC, server_maker_.MakeConnectivityProbingPacket( + server_packet_num++, false)); + // Ping packet to send after migration is completed. + if (i == 0) { + // First ack and PING are bundled, and version flag is set. + quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeAckAndPingPacket( + packet_number++, false, 1, 1, 1)); + } else if (i != 4) { + // ACK and PING post migration after successful probing. + quic_data2.AddWrite( + SYNCHRONOUS, client_maker_.MakeAckPacket(packet_number++, 1 + 2 * i, + 1 + 2 * i, 1, true)); + quic_data2.AddWrite(SYNCHRONOUS, + client_maker_.MakePingPacket(packet_number++, false)); + } + if (i == 4) { + // Add one more synchronous read on the last probing reader. The + // reader should be deleted on the read before this one. + // The test will verify this read is not consumed. + quic_data2.AddRead(SYNCHRONOUS, + server_maker_.MakeConnectivityProbingPacket( + server_packet_num++, false)); + } else { + quic_data2.AddRead(ASYNC, server_maker_.MakeConnectivityProbingPacket( + server_packet_num++, false)); + } + if (i == 3) { + // On the last allowed port migration, read one more packet so + // that ACK is sent. The next round of migration (which hists the limit) + // will not send any proactive ACK when reading the successful probing + // response. + quic_data2.AddRead(ASYNC, server_maker_.MakeConnectivityProbingPacket( + server_packet_num++, false)); + quic_data2.AddWrite(SYNCHRONOUS, client_maker_.MakeAckPacket( + packet_number++, 9, 9, 1, true)); + } + quic_data2.AddRead(SYNCHRONOUS, ERR_IO_PENDING); // EOF. + quic_data2.AddSocketDataToFactory(socket_factory_.get()); + + // Cause the connection to report path degrading to the session. + // Session will start to probe a different port. + session->connection()->OnPathDegradingTimeout(); + + // Next connectivity probe is scheduled to be sent in 2 * + // kDefaultRTTMilliSecs. + EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); + next_task_delay = task_runner->NextPendingTaskDelay(); + EXPECT_EQ(base::TimeDelta::FromMilliseconds(2 * kDefaultRTTMilliSecs), + next_task_delay); + + // The connection should still be alive, and not marked as going away. + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + + // Resume quic data and a connectivity probe response will be read on the + // new socket. + quic_data2.Resume(); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + EXPECT_EQ(1u, session->GetNumActiveStreams()); + + if (i < 4) { + // There should be pending tasks, the nearest one will complete + // migration to the new port. + EXPECT_EQ(2u, task_runner->GetPendingTaskCount()); + next_task_delay = task_runner->NextPendingTaskDelay(); + EXPECT_EQ(base::TimeDelta(), next_task_delay); + } else { + // Last attempt to migrate will abort due to hitting the limit of max + // number of allowed migrations. + EXPECT_EQ(1u, task_runner->GetPendingTaskCount()); + next_task_delay = task_runner->NextPendingTaskDelay(); + EXPECT_NE(base::TimeDelta(), next_task_delay); + } + task_runner->FastForwardBy(next_task_delay); + EXPECT_TRUE(quic_data2.AllWriteDataConsumed()); + // The last round of migration will abort upon reading the probing response. + // Future reads in the same socket is ignored. + EXPECT_EQ(i != 4, quic_data2.AllReadDataConsumed()); + } + + EXPECT_EQ(0u, task_runner->GetPendingTaskCount()); + + // Verify that the session is still alive. + EXPECT_TRUE(QuicStreamFactoryPeer::IsLiveSession(factory_.get(), session)); + EXPECT_TRUE(HasActiveSession(host_port_pair_)); + + stream.reset(); + EXPECT_TRUE(quic_data1.AllReadDataConsumed()); + EXPECT_TRUE(quic_data1.AllWriteDataConsumed()); +} + // This test verifies that the session marks itself GOAWAY on path degrading // and it does not receive any new request TEST_P(QuicStreamFactoryTest, GoawayOnPathDegrading) {
diff --git a/net/socket/socket_bio_adapter.cc b/net/socket/socket_bio_adapter.cc index 6f134af6..182b9d6 100644 --- a/net/socket/socket_bio_adapter.cc +++ b/net/socket/socket_bio_adapter.cc
@@ -22,7 +22,7 @@ namespace { -net::NetworkTrafficAnnotationTag kTrafficAnnotation = +const net::NetworkTrafficAnnotationTag kTrafficAnnotation = net::DefineNetworkTrafficAnnotation("socket_bio_adapter", R"( semantics { sender: "Socket BIO Adapter"
diff --git a/net/spdy/platform/impl/spdy_string_utils_impl.h b/net/spdy/platform/impl/spdy_string_utils_impl.h index f9cbf6f6..a621809 100644 --- a/net/spdy/platform/impl/spdy_string_utils_impl.h +++ b/net/spdy/platform/impl/spdy_string_utils_impl.h
@@ -35,7 +35,10 @@ } inline std::string SpdyHexDecodeImpl(SpdyStringPiece data) { - return net::HexDecode(data); + std::string result; + if (!base::HexStringToString(data, &result)) + result.clear(); + return result; } NET_EXPORT_PRIVATE bool SpdyHexDecodeToUInt32Impl(SpdyStringPiece data,
diff --git a/net/test/ct_test_util.cc b/net/test/ct_test_util.cc index 24b3f3a..d01b59ca1 100644 --- a/net/test/ct_test_util.cc +++ b/net/test/ct_test_util.cc
@@ -164,6 +164,13 @@ "d3"; size_t kSampleSTHTreeSize = 21u; +std::string HexDecode(base::StringPiece input) { + std::string result; + if (!base::HexStringToString(input, &result)) + result.clear(); + return result; +} + } // namespace void GetX509CertSignedEntry(SignedEntryData* entry) {
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 4cd5630..0add3e8a 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -642,8 +642,11 @@ maybe_stored_cookies_.clear(); GURL referrer_url(referrer_); + bool same_origin_for_metrics; + if (referrer_url != URLRequestJob::ComputeReferrerForPolicy( - referrer_policy_, referrer_url, initiator_, url())) { + referrer_policy_, referrer_url, initiator_, url(), + &same_origin_for_metrics)) { if (!network_delegate_ || !network_delegate_->CancelURLRequestWithPolicyViolatingReferrerHeader( *this, url(), referrer_url)) { @@ -660,6 +663,8 @@ } } + RecordReferrerGranularityMetrics(same_origin_for_metrics); + // Start() always completes asynchronously. // // Status is generally set by URLRequestJob itself, but Start() calls @@ -1102,6 +1107,31 @@ delegate_event_type_ = NetLogEventType::FAILED; } +void URLRequest::RecordReferrerGranularityMetrics( + bool request_is_same_origin) const { + GURL referrer_url(referrer_); + bool referrer_more_descriptive_than_its_origin = + referrer_url.is_valid() && referrer_url.PathForRequestPiece().size() > 1; + + // To avoid renaming the existing enum, we have to use the three-argument + // histogram macro. + if (request_is_same_origin) { + UMA_HISTOGRAM_ENUMERATION( + "Net.URLRequest.ReferrerPolicyForRequest.SameOrigin", referrer_policy_, + MAX_REFERRER_POLICY + 1); + UMA_HISTOGRAM_BOOLEAN( + "Net.URLRequest.ReferrerHasInformativePath.SameOrigin", + referrer_more_descriptive_than_its_origin); + } else { + UMA_HISTOGRAM_ENUMERATION( + "Net.URLRequest.ReferrerPolicyForRequest.CrossOrigin", referrer_policy_, + MAX_REFERRER_POLICY + 1); + UMA_HISTOGRAM_BOOLEAN( + "Net.URLRequest.ReferrerHasInformativePath.CrossOrigin", + referrer_more_descriptive_than_its_origin); + } +} + void URLRequest::GetConnectionAttempts(ConnectionAttempts* out) const { if (job_) job_->GetConnectionAttempts(out);
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h index 7d1b86c..672a5f93 100644 --- a/net/url_request/url_request.h +++ b/net/url_request/url_request.h
@@ -93,32 +93,37 @@ // of the initial leg of the request; the caller is responsible for // setting the initial Referer, and the ReferrerPolicy only controls // what happens to the Referer while following redirects. + // + // NOTE: This enum is persisted to histograms. Do not change or reorder + // values. + // TODO(~M82): Once the Net.URLRequest.ReferrerPolicyForRequest + // metric is retired, remove this notice. enum ReferrerPolicy { // Clear the referrer header if the header value is HTTPS but the request // destination is HTTP. This is the default behavior of URLRequest. - CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE = 0, // A slight variant on CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: // If the request destination is HTTP, an HTTPS referrer will be cleared. If // the request's destination is cross-origin with the referrer (but does not // downgrade), the referrer's granularity will be stripped down to an origin // rather than a full URL. Same-origin requests will send the full referrer. - REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN, + REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN = 1, // Strip the referrer down to an origin when the origin of the referrer is // different from the destination's origin. - ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN, + ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN = 2, // Never change the referrer. - NEVER_CLEAR_REFERRER, + NEVER_CLEAR_REFERRER = 3, // Strip the referrer down to the origin regardless of the redirect // location. - ORIGIN, + ORIGIN = 4, // Clear the referrer when the request's referrer is cross-origin with // the request's destination. - CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN, + CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN = 5, // Strip the referrer down to the origin, but clear it entirely if the // referrer value is HTTPS and the destination is HTTP. - ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE, + ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE = 6, // Always clear the referrer regardless of the request destination. - NO_REFERRER, + NO_REFERRER = 7, MAX_REFERRER_POLICY = NO_REFERRER }; @@ -819,6 +824,12 @@ // cancellation. void OnCallToDelegateComplete(); + // Records the referrer policy of the given request, bucketed by + // whether the request is same-origin or not. To save computation, + // takes this fact as a boolean parameter rather than dynamically + // checking. + void RecordReferrerGranularityMetrics(bool request_is_same_origin) const; + // Contextual information used for this request. Cannot be NULL. This contains // most of the dependencies which are shared between requests (disk cache, // cookie store, socket pool, etc.)
diff --git a/net/url_request/url_request_data_job.cc b/net/url_request/url_request_data_job.cc deleted file mode 100644 index b4b67aa..0000000 --- a/net/url_request/url_request_data_job.cc +++ /dev/null
@@ -1,48 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// Simple implementation of a data: protocol handler. - -#include "net/url_request/url_request_data_job.h" - -#include "net/base/data_url.h" -#include "net/base/net_errors.h" -#include "net/http/http_response_headers.h" -#include "url/gurl.h" - -namespace net { - -int URLRequestDataJob::BuildResponse(const GURL& url, - base::StringPiece method, - std::string* mime_type, - std::string* charset, - std::string* data, - HttpResponseHeaders* headers) { - return DataURL::BuildResponse(url, method, mime_type, charset, data, headers); -} - -URLRequestDataJob::URLRequestDataJob( - URLRequest* request, NetworkDelegate* network_delegate) - : URLRequestSimpleJob(request, network_delegate) { -} - -int URLRequestDataJob::GetData(std::string* mime_type, - std::string* charset, - std::string* data, - CompletionOnceCallback callback) const { - // Check if data URL is valid. If not, don't bother to try to extract data. - // Otherwise, parse the data from the data URL. - const GURL& url = request_->url(); - if (!url.is_valid()) - return ERR_INVALID_URL; - - // TODO(tyoshino): Get the headers and export via - // URLRequestJob::GetResponseInfo(). - return BuildResponse(url, request_->method(), mime_type, charset, data, - nullptr); -} - -URLRequestDataJob::~URLRequestDataJob() = default; - -} // namespace net
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc index e3d59c2..0246372 100644 --- a/net/url_request/url_request_job.cc +++ b/net/url_request/url_request_job.cc
@@ -278,7 +278,8 @@ URLRequest::ReferrerPolicy policy, const GURL& original_referrer, const base::Optional<url::Origin>& initiator, - const GURL& destination) { + const GURL& destination, + bool* same_origin_out_for_metrics) { bool secure_referrer_but_insecure_destination = original_referrer.SchemeIsCryptographic() && !destination.SchemeIsCryptographic(); @@ -286,6 +287,8 @@ url::Origin initiator_origin = initiator.value_or(referrer_origin); bool same_origin = initiator_origin.IsSameOriginWith(url::Origin::Create(destination)); + if (same_origin_out_for_metrics) + *same_origin_out_for_metrics = same_origin; switch (policy) { case URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE: return secure_referrer_but_insecure_destination ? GURL()
diff --git a/net/url_request/url_request_job.h b/net/url_request/url_request_job.h index 56d32806..3d372b3 100644 --- a/net/url_request/url_request_job.h +++ b/net/url_request/url_request_job.h
@@ -246,11 +246,18 @@ // returns the referrer URL mandated by |request|'s referrer policy. If the // initiator does not have a value, which is the case for many // browser-initiated requests, we fallback to using the origin of |referrer|. + // + // If |same_origin_out_for_metrics| is non-null, saves to + // |*same_origin_out_for_metrics| whether |initiator| and |destination| are + // cross-origin. + // (This allows reporting in a UMA whether the request is same-origin, without + // recomputing that information.) static GURL ComputeReferrerForPolicy( URLRequest::ReferrerPolicy policy, const GURL& original_referrer, const base::Optional<url::Origin>& initiator, - const GURL& destination); + const GURL& destination, + bool* same_origin_out_for_metrics = nullptr); protected: // Notifies the job that a certificate is requested.
diff --git a/net/url_request/url_request_job_unittest.cc b/net/url_request/url_request_job_unittest.cc index 66dbc2df..055d4ec 100644 --- a/net/url_request/url_request_job_unittest.cc +++ b/net/url_request/url_request_job_unittest.cc
@@ -635,4 +635,28 @@ RemoveMockTransaction(&kBrotliSlowTransaction); } +TEST(URLRequestJobComputeReferrer, SetsSameOriginForMetricsOnSameOrigin) { + bool same_origin = false; + URLRequestJob::ComputeReferrerForPolicy( + URLRequest::ReferrerPolicy(), /*original_referrer=*/GURL(), + url::Origin::Create(GURL("http://google.com")), + /*destination=*/GURL("http://google.com"), &same_origin); + EXPECT_TRUE(same_origin); +} + +TEST(URLRequestJobComputeReferrer, SetsSameOriginForMetricsOnCrossOrigin) { + bool same_origin = true; + URLRequestJob::ComputeReferrerForPolicy( + URLRequest::ReferrerPolicy(), /*original_referrer=*/GURL(), + url::Origin::Create(GURL("http://google.com")), + /*destination=*/GURL("http://boggle.com"), &same_origin); + EXPECT_FALSE(same_origin); +} + +TEST(URLRequestJobComputeReferrer, AcceptsNullptrInput) { + // Shouldn't segfault. + URLRequestJob::ComputeReferrerForPolicy(URLRequest::ReferrerPolicy(), GURL(), + base::nullopt, GURL(), nullptr); +} + } // namespace net
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index f6cf52d..5df08d1 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -800,6 +800,178 @@ EXPECT_TRUE(d.request_failed()); } +TEST_F(URLRequestTest, RecordsSameOriginReferrerHistogram) { + TestURLRequestContext context; + TestNetworkDelegate network_delegate; + network_delegate.set_cancel_request_with_policy_violating_referrer(false); + context.set_network_delegate(&network_delegate); + TestDelegate d; + std::unique_ptr<URLRequest> req( + context.CreateRequest(GURL("http://google.com/"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + req->set_initiator(url::Origin::Create(GURL("http://google.com"))); + req->set_referrer_policy(URLRequest::NEVER_CLEAR_REFERRER); + + base::HistogramTester histograms; + + req->Start(); + d.RunUntilComplete(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerPolicyForRequest.SameOrigin", + static_cast<int>(URLRequest::NEVER_CLEAR_REFERRER), 1); +} + +TEST_F(URLRequestTest, RecordsCrossOriginReferrerHistogram) { + TestURLRequestContext context; + TestNetworkDelegate network_delegate; + context.set_network_delegate(&network_delegate); + TestDelegate d; + std::unique_ptr<URLRequest> req( + context.CreateRequest(GURL("http://google.com/"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + req->set_initiator(url::Origin::Create(GURL("http://origin.com"))); + + // Set a different policy just to make sure we aren't always logging the same + // policy. + req->set_referrer_policy( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE); + + base::HistogramTester histograms; + + req->Start(); + d.RunUntilComplete(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerPolicyForRequest.CrossOrigin", + static_cast<int>( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE), + 1); +} + +TEST_F(URLRequestTest, RecordsReferrerHistogramAgainOnRedirect) { + TestURLRequestContext context; + BlockingNetworkDelegate network_delegate( + BlockingNetworkDelegate::SYNCHRONOUS); + network_delegate.set_redirect_url(GURL("http://redirect.com/")); + context.set_network_delegate(&network_delegate); + TestDelegate d; + std::unique_ptr<URLRequest> req( + context.CreateRequest(GURL("http://google.com/"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + req->set_initiator(url::Origin::Create(GURL("http://google.com"))); + + req->set_referrer_policy( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE); + + base::HistogramTester histograms; + + req->Start(); + d.RunUntilRedirect(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerPolicyForRequest.SameOrigin", + static_cast<int>( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE), + 1); + req->FollowDeferredRedirect(/*removed_headers=*/base::nullopt, + /*modified_headers=*/base::nullopt); + d.RunUntilComplete(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerPolicyForRequest.CrossOrigin", + static_cast<int>( + URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE), + 1); +} + +TEST_F(URLRequestTest, RecordsReferrrerWithInformativePath) { + TestURLRequestContext context; + BlockingNetworkDelegate network_delegate( + BlockingNetworkDelegate::SYNCHRONOUS); + network_delegate.set_cancel_request_with_policy_violating_referrer(true); + context.set_network_delegate(&network_delegate); + network_delegate.set_redirect_url(GURL("http://redirect.com/")); + TestDelegate d; + std::unique_ptr<URLRequest> req( + context.CreateRequest(GURL("http://google.com/"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + + // Since this referrer is much more informative than the initiating origin, + // we should see the histograms' true buckets populated. + req->SetReferrer("http://google.com/very-informative-path"); + + base::HistogramTester histograms; + + req->Start(); + d.RunUntilRedirect(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerHasInformativePath.SameOrigin", + /* Check the count of the "true" bucket in the boolean histogram. */ true, + 1); + req->FollowDeferredRedirect(/*removed_headers=*/base::nullopt, + /*modified_headers=*/base::nullopt); + d.RunUntilComplete(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerHasInformativePath.CrossOrigin", true, 1); +} + +TEST_F(URLRequestTest, RecordsReferrerWithInformativeQuery) { + TestURLRequestContext context; + BlockingNetworkDelegate network_delegate( + BlockingNetworkDelegate::SYNCHRONOUS); + network_delegate.set_cancel_request_with_policy_violating_referrer(true); + context.set_network_delegate(&network_delegate); + network_delegate.set_redirect_url(GURL("http://redirect.com/")); + TestDelegate d; + std::unique_ptr<URLRequest> req( + context.CreateRequest(GURL("http://google.com/"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + + // Since this referrer is much more informative than the initiating origin, + // we should see the histograms' true buckets populated. + req->SetReferrer("http://google.com/?very-informative-query"); + + base::HistogramTester histograms; + + req->Start(); + d.RunUntilRedirect(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerHasInformativePath.SameOrigin", + /* Check the count of the "true" bucket in the boolean histogram. */ true, + 1); + req->FollowDeferredRedirect(/*removed_headers=*/base::nullopt, + /*modified_headers=*/base::nullopt); + d.RunUntilComplete(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerHasInformativePath.CrossOrigin", true, 1); +} + +TEST_F(URLRequestTest, RecordsReferrerWithoutInformativePathOrQuery) { + TestURLRequestContext context; + BlockingNetworkDelegate network_delegate( + BlockingNetworkDelegate::SYNCHRONOUS); + network_delegate.set_cancel_request_with_policy_violating_referrer(false); + context.set_network_delegate(&network_delegate); + network_delegate.set_redirect_url(GURL("http://origin.com/")); + TestDelegate d; + std::unique_ptr<URLRequest> req( + context.CreateRequest(GURL("http://google.com/"), DEFAULT_PRIORITY, &d, + TRAFFIC_ANNOTATION_FOR_TESTS)); + + // Since this referrer _isn't_ more informative than the initiating origin, + // we should see the histograms' false buckets populated. + req->SetReferrer("http://origin.com"); + + base::HistogramTester histograms; + + req->Start(); + d.RunUntilRedirect(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerHasInformativePath.CrossOrigin", false, 1); + req->FollowDeferredRedirect(/*removed_headers=*/base::nullopt, + /*modified_headers=*/base::nullopt); + d.RunUntilComplete(); + histograms.ExpectUniqueSample( + "Net.URLRequest.ReferrerHasInformativePath.SameOrigin", false, 1); +} + // An Interceptor for use with interceptor tests. class MockURLRequestInterceptor : public URLRequestInterceptor { public:
diff --git a/remoting/tools/mac/chromoting-set-channel.sh b/remoting/tools/mac/chromoting-set-channel.sh deleted file mode 100755 index ab1e37a9..0000000 --- a/remoting/tools/mac/chromoting-set-channel.sh +++ /dev/null
@@ -1,68 +0,0 @@ -#!/bin/sh - -# Copyright (c) 2012 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -set -e -u - -ME="$(basename "$0")" -readonly ME - -KSADMIN=/Library/Google/GoogleSoftwareUpdate/GoogleSoftwareUpdate.bundle/Contents/MacOS/ksadmin -KSPID=com.google.chrome_remote_desktop - -usage() { - echo "Usage: ${ME} <channel>" >&2 - echo "where <channel> is 'beta' or 'stable'" >&2 -} - -log() { - local message="$1" - echo "${message}" - logger "${message}" -} - -checkroot() { - if [[ "$(id -u)" != "0" ]]; then - echo "This script requires root permissions" 1>&2 - exit 1 - fi -} - -main() { - local channel="$1" - - if [[ "${channel}" != "beta" && "${channel}" != "stable" ]]; then - usage - exit 1 - fi - - local channeltag="${channel}" - if [[ "${channel}" == "stable" ]]; then - channeltag="" - fi - - log "Switching Chrome Remote Desktop channel to ${channel}" - - $KSADMIN --productid "$KSPID" --tag "${channeltag}" - - if [[ "${channel}" == "stable" ]]; then - echo "You're not done yet!" - echo "You must now UNINSTALL and RE-INSTALL the latest version of Chrome" - echo "Remote Desktop to get your machine back on the stable channel." - echo "Thank you!" - else - echo "Switch to ${channel} channel complete." - echo "You will download ${channel} binaries during the next update check." - fi -} - -checkroot - -if [[ $# < 1 ]]; then - usage - exit 1 -fi - -main "$@"
diff --git a/remoting/tools/win/chromoting-set-channel.bat b/remoting/tools/win/chromoting-set-channel.bat deleted file mode 100755 index 35c03fa..0000000 --- a/remoting/tools/win/chromoting-set-channel.bat +++ /dev/null
@@ -1,49 +0,0 @@ -@echo off - -REM Copyright (c) 2012 The Chromium Authors. All rights reserved. -REM Use of this source code is governed by a BSD-style license that can be -REM found in the LICENSE file. - -set CHANNEL=%1 - -REM Check if we are running as an Administrator. -REM Based on method described at: -REM http://stackoverflow.com/questions/4051883/batch-script-how-to-check-for-admin-rights -net session >nul 2>&1 -if not %errorlevel% equ 0 ( - echo This script updates the registry and needs to be run as Administrator. - echo Right-click "Command Prompt" and select "Run as Administrator" and run - echo this script from there. - goto :eof -) - -REM Make sure the argument specifies a valid channel. -if "_%CHANNEL%_"=="_beta_" goto validarg -if "_%CHANNEL%_"=="_stable_" goto validarg -goto usage - -:validarg -set SYSTEM32=%SystemRoot%\system32 -if "_%PROCESSOR_ARCHITECTURE%_"=="_AMD64_" set SYSTEM32=%SystemRoot%\syswow64 - -set REGKEY="HKLM\SOFTWARE\Google\Update\ClientState\{B210701E-FFC4-49E3-932B-370728C72662}" -set VALUENAME=ap - -if "_%CHANNEL%_"=="_stable_" ( - %SYSTEM32%\reg.exe delete %REGKEY% /v %VALUENAME% /f - echo ******************** - echo You're not done yet! - echo ******************** - echo You must now UNINSTALL and RE-INSTALL the latest version of Chrome - echo Remote Desktop to get your machine back on the stable channel. - echo Thank you! -) else ( - %SYSTEM32%\reg.exe add %REGKEY% /v %VALUENAME% /d %CHANNEL% /f - echo Switch to %CHANNEL% channel complete. - echo You will automatically get %CHANNEL% binaries during the next update. -) -goto :eof - -:usage -echo Usage: %0 ^<channel^> -echo where ^<channel^> is 'beta' or 'stable'.
diff --git a/services/data_decoder/data_decoder_service.cc b/services/data_decoder/data_decoder_service.cc index 375c074..b365a374 100644 --- a/services/data_decoder/data_decoder_service.cc +++ b/services/data_decoder/data_decoder_service.cc
@@ -32,14 +32,14 @@ DataDecoderService::DataDecoderService( mojo::PendingReceiver<mojom::DataDecoderService> receiver) { - receiver_.Bind(std::move(receiver)); + receivers_.Add(this, std::move(receiver)); } DataDecoderService::~DataDecoderService() = default; void DataDecoderService::BindReceiver( mojo::PendingReceiver<mojom::DataDecoderService> receiver) { - receiver_.Bind(std::move(receiver)); + receivers_.Add(this, std::move(receiver)); } void DataDecoderService::BindImageDecoder(
diff --git a/services/data_decoder/data_decoder_service.h b/services/data_decoder/data_decoder_service.h index 884bb7ebb..36fc4b55 100644 --- a/services/data_decoder/data_decoder_service.h +++ b/services/data_decoder/data_decoder_service.h
@@ -9,7 +9,7 @@ #include "base/macros.h" #include "mojo/public/cpp/bindings/pending_receiver.h" -#include "mojo/public/cpp/bindings/receiver.h" +#include "mojo/public/cpp/bindings/receiver_set.h" #include "services/data_decoder/public/mojom/bundled_exchanges_parser.mojom.h" #include "services/data_decoder/public/mojom/data_decoder_service.mojom.h" #include "services/data_decoder/public/mojom/image_decoder.mojom.h" @@ -61,7 +61,9 @@ mojo::PendingReceiver<mojom::BleScanParser> receiver) override; #endif // OS_CHROMEOS - mojo::Receiver<mojom::DataDecoderService> receiver_{this}; + // In-process instances (e.g. on iOS or in tests) may have multiple concurrent + // remote DataDecoderService clients. + mojo::ReceiverSet<mojom::DataDecoderService> receivers_; bool drop_image_decoders_ = false; bool drop_json_parsers_ = false;
diff --git a/services/preferences/tracked/pref_hash_calculator.cc b/services/preferences/tracked/pref_hash_calculator.cc index fe62ab8..0a6cdb7 100644 --- a/services/preferences/tracked/pref_hash_calculator.cc +++ b/services/preferences/tracked/pref_hash_calculator.cc
@@ -37,11 +37,9 @@ const std::string& message, const std::string& digest_string) { crypto::HMAC hmac(crypto::HMAC::SHA256); - std::vector<uint8_t> digest; - return base::HexStringToBytes(digest_string, &digest) && hmac.Init(key) && - hmac.Verify(message, - base::StringPiece(reinterpret_cast<char*>(&digest[0]), - digest.size())); + std::string digest; + return base::HexStringToString(digest_string, &digest) && hmac.Init(key) && + hmac.Verify(message, digest); } // Renders |value| as a string. |value| may be NULL, in which case the result
diff --git a/services/tracing/BUILD.gn b/services/tracing/BUILD.gn index 389a7cb..72ad733 100644 --- a/services/tracing/BUILD.gn +++ b/services/tracing/BUILD.gn
@@ -16,14 +16,10 @@ sources = [ "perfetto/consumer_host.cc", "perfetto/consumer_host.h", - "perfetto/json_trace_exporter.cc", - "perfetto/json_trace_exporter.h", "perfetto/perfetto_service.cc", "perfetto/perfetto_service.h", "perfetto/producer_host.cc", "perfetto/producer_host.h", - "perfetto/track_event_json_exporter.cc", - "perfetto/track_event_json_exporter.h", "tracing_service.cc", "tracing_service.h", ] @@ -40,31 +36,40 @@ ] deps = [ - "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite", + "//third_party/perfetto:libproto_to_json", ] } -executable("trace_json_exporter") { +source_set("json_trace_exporter") { sources = [ - "perfetto/json_exporter_main.cc", "perfetto/json_trace_exporter.cc", "perfetto/json_trace_exporter.h", "perfetto/track_event_json_exporter.cc", "perfetto/track_event_json_exporter.h", ] - - configs += [ "//build/config/compiler:rtti" ] - deps = [ "//base", "//third_party/perfetto:libperfetto", - "//third_party/perfetto/include/perfetto/protozero:protozero", "//third_party/perfetto/protos/perfetto/common:lite", "//third_party/perfetto/protos/perfetto/trace:lite", "//third_party/perfetto/protos/perfetto/trace/chrome:lite", "//third_party/perfetto/protos/perfetto/trace/chrome:minimal_complete_lite", "//third_party/perfetto/protos/perfetto/trace/interned_data:lite", "//third_party/perfetto/protos/perfetto/trace/track_event:lite", + ] +} + +executable("trace_json_exporter") { + sources = [ + "perfetto/json_exporter_main.cc", + ] + + configs += [ "//build/config/compiler:rtti" ] + + deps = [ + ":json_trace_exporter", + "//base", + "//third_party/perfetto:libperfetto", "//third_party/perfetto/src/protozero:protozero", ] } @@ -145,6 +150,7 @@ } deps = [ + ":json_trace_exporter", ":lib", ":test_utils", "//base",
diff --git a/services/tracing/perfetto/consumer_host.cc b/services/tracing/perfetto/consumer_host.cc index aa254286..ee60eaab 100644 --- a/services/tracing/perfetto/consumer_host.cc +++ b/services/tracing/perfetto/consumer_host.cc
@@ -24,13 +24,15 @@ #include "mojo/public/cpp/bindings/self_owned_receiver.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "mojo/public/cpp/system/wait.h" -#include "services/tracing/perfetto/json_trace_exporter.h" #include "services/tracing/perfetto/perfetto_service.h" -#include "services/tracing/perfetto/track_event_json_exporter.h" #include "services/tracing/public/cpp/trace_event_args_whitelist.h" +#include "third_party/perfetto/include/perfetto/ext/trace_processor/export_json.h" #include "third_party/perfetto/include/perfetto/ext/tracing/core/observable_events.h" +#include "third_party/perfetto/include/perfetto/ext/tracing/core/slice.h" #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_packet.h" #include "third_party/perfetto/include/perfetto/ext/tracing/core/trace_stats.h" +#include "third_party/perfetto/include/perfetto/trace_processor/basic_types.h" +#include "third_party/perfetto/include/perfetto/trace_processor/trace_processor_storage.h" #include "third_party/perfetto/include/perfetto/tracing/core/trace_config.h" #include "third_party/perfetto/protos/perfetto/config/trace_config.pb.h" @@ -40,6 +42,44 @@ const int32_t kEnableTracingTimeoutSeconds = 10; +class JsonStringOutputWriter + : public perfetto::trace_processor::json::OutputWriter { + public: + using FlushCallback = + base::RepeatingCallback<void(std::string json, bool has_more)>; + + JsonStringOutputWriter(FlushCallback flush_callback) + : flush_callback_(std::move(flush_callback)) { + buffer_.reserve(kBufferReserveCapacity); + } + + ~JsonStringOutputWriter() override { + flush_callback_.Run(std::move(buffer_), false); + } + + perfetto::trace_processor::util::Status AppendString( + const std::string& string) override { + buffer_ += string; + if (buffer_.size() > kBufferLimitInBytes) { + flush_callback_.Run(std::move(buffer_), true); + // Reset the buffer_ after moving it above. + buffer_.clear(); + buffer_.reserve(kBufferReserveCapacity); + } + return perfetto::trace_processor::util::OkStatus(); + } + + private: + static constexpr size_t kBufferLimitInBytes = 100 * 1024; + // Since we write each string before checking the limit, we'll always go + // slightly over and hence we reserve some extra space to avoid most + // reallocs. + static constexpr size_t kBufferReserveCapacity = kBufferLimitInBytes * 5 / 4; + + FlushCallback flush_callback_; + std::string buffer_; +}; + } // namespace class ConsumerHost::StreamWriter { @@ -291,7 +331,7 @@ tracing_session_client_->OnTracingDisabled(); - if (json_trace_exporter_) { + if (trace_processor_) { host_->consumer_endpoint()->ReadBuffers(); } @@ -343,6 +383,24 @@ weak_factory_.GetWeakPtr()), base::SequencedTaskRunnerHandle::Get()); + if (privacy_filtering_enabled) { + // For filtering/whitelisting to be possible at JSON export time, + // filtering must not have been enabled during proto emission time + // (or there's nothing to pass through the whitelist). + DCHECK(!privacy_filtering_enabled_); + privacy_filtering_enabled_ = true; + } + + json_agent_label_filter_ = agent_label_filter; + + trace_processor_ = + perfetto::trace_processor::TraceProcessorStorage::CreateInstance( + perfetto::trace_processor::Config()); + + DisableTracing(); +} + +void ConsumerHost::TracingSession::ExportJson() { // In legacy backend, the trace event agent sets the predicate used by // TraceLog. For perfetto backend, ensure that predicate is always set // before creating the exporter. The agent can be created later than this @@ -356,34 +414,55 @@ base::BindRepeating(&IsMetadataWhitelisted)); } - JSONTraceExporter::ArgumentFilterPredicate arg_filter_predicate; - JSONTraceExporter::MetadataFilterPredicate metadata_filter_predicate; - if (privacy_filtering_enabled) { - // For filtering/whitelisting to be possible at JSON export time, - // filtering must not have been enabled during proto emission time - // (or there's nothing to pass through the whitelist). - DCHECK(!privacy_filtering_enabled_); + perfetto::trace_processor::json::ArgumentFilterPredicate argument_filter; + perfetto::trace_processor::json::MetadataFilterPredicate metadata_filter; + perfetto::trace_processor::json::LabelFilterPredicate label_filter; + + if (privacy_filtering_enabled_) { auto* trace_log = base::trace_event::TraceLog::GetInstance(); - arg_filter_predicate = trace_log->GetArgumentFilterPredicate(); - metadata_filter_predicate = trace_log->GetMetadataFilterPredicate(); + base::trace_event::ArgumentFilterPredicate argument_filter_predicate = + trace_log->GetArgumentFilterPredicate(); + argument_filter = + [argument_filter_predicate]( + const char* category_group_name, const char* event_name, + perfetto::trace_processor::json::ArgumentNameFilterPredicate* + name_filter) { + base::trace_event::ArgumentNameFilterPredicate name_filter_predicate; + bool result = argument_filter_predicate.Run( + category_group_name, event_name, &name_filter_predicate); + if (name_filter_predicate) { + *name_filter = [name_filter_predicate](const char* arg_name) { + return name_filter_predicate.Run(arg_name); + }; + } + return result; + }; + base::trace_event::MetadataFilterPredicate metadata_filter_predicate = + trace_log->GetMetadataFilterPredicate(); + metadata_filter = [metadata_filter_predicate](const char* metadata_name) { + return metadata_filter_predicate.Run(metadata_name); + }; } - json_trace_exporter_ = std::make_unique<TrackEventJSONExporter>( - std::move(arg_filter_predicate), std::move(metadata_filter_predicate), - base::BindRepeating(&ConsumerHost::TracingSession::OnJSONTraceData, - base::Unretained(this))); - json_trace_exporter_->set_label_filter(agent_label_filter); + if (!json_agent_label_filter_.empty()) { + label_filter = [this](const char* label) { + return strcmp(label, json_agent_label_filter_.c_str()) == 0; + }; + } - DisableTracing(); + JsonStringOutputWriter output_writer(base::BindRepeating( + &ConsumerHost::TracingSession::OnJSONTraceData, base::Unretained(this))); + auto status = perfetto::trace_processor::json::ExportJson( + trace_processor_.get(), &output_writer, argument_filter, metadata_filter, + label_filter); + DCHECK(status.ok()) << status.message(); } -void ConsumerHost::TracingSession::OnJSONTraceData( - std::string* json, - base::DictionaryValue* metadata, - bool has_more) { +void ConsumerHost::TracingSession::OnJSONTraceData(std::string json, + bool has_more) { auto slices = std::make_unique<StreamWriter::Slices>(); slices->push_back(std::string()); - slices->back().swap(*json); + slices->back().swap(json); read_buffers_stream_writer_.Post(FROM_HERE, &StreamWriter::WriteToStream, std::move(slices), has_more); @@ -396,10 +475,40 @@ std::vector<perfetto::TracePacket> packets, bool has_more) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - if (json_trace_exporter_) { - json_trace_exporter_->OnTraceData(std::move(packets), has_more); + if (trace_processor_) { + // Calculate space needed for trace chunk. Each packet has a preamble and + // payload size. + size_t max_size = packets.size() * perfetto::TracePacket::kMaxPreambleBytes; + for (const auto& packet : packets) { + max_size += packet.size(); + } + + // Copy packets into a trace file chunk. + size_t position = 0; + std::unique_ptr<uint8_t[]> data(new uint8_t[max_size]); + for (perfetto::TracePacket& packet : packets) { + char* preamble; + size_t preamble_size; + std::tie(preamble, preamble_size) = packet.GetProtoPreamble(); + DCHECK_LT(position + preamble_size, max_size); + memcpy(&data[position], preamble, preamble_size); + position += preamble_size; + for (const perfetto::Slice& slice : packet.slices()) { + DCHECK_LT(position + slice.size, max_size); + memcpy(&data[position], slice.start, slice.size); + position += slice.size; + } + } + + auto status = trace_processor_->Parse(std::move(data), position); + // TODO(eseckler): There's no way to propagate this error at the moment - If + // one occurs on production builds, we silently ignore it and will end up + // producing an empty JSON result. + DCHECK(status.ok()) << status.message(); if (!has_more) { - json_trace_exporter_.reset(); + trace_processor_->NotifyEndOfFile(); + ExportJson(); + trace_processor_.reset(); } return; }
diff --git a/services/tracing/perfetto/consumer_host.h b/services/tracing/perfetto/consumer_host.h index 63a400ca..64031683 100644 --- a/services/tracing/perfetto/consumer_host.h +++ b/services/tracing/perfetto/consumer_host.h
@@ -23,17 +23,18 @@ #include "third_party/perfetto/include/perfetto/ext/tracing/core/consumer.h" #include "third_party/perfetto/include/perfetto/ext/tracing/core/tracing_service.h" -namespace base { -class DictionaryValue; -} - namespace service_manager { struct BindSourceInfo; } // namespace service_manager +namespace perfetto { +namespace trace_processor { +class TraceProcessorStorage; +} // namespace trace_processor +} // namespace perfetto + namespace tracing { -class JSONTraceExporter; class PerfettoService; // This is a Mojo interface which enables any client @@ -89,9 +90,8 @@ DisableTracingAndEmitJsonCallback callback) override; private: - void OnJSONTraceData(std::string* json, - base::DictionaryValue* metadata, - bool has_more); + void ExportJson(); + void OnJSONTraceData(std::string json, bool has_more); void OnEnableTracingTimeout(); void MaybeSendEnableTracingAck(); bool IsExpectedPid(base::ProcessId pid) const; @@ -102,7 +102,9 @@ bool privacy_filtering_enabled_ = false; base::SequenceBound<StreamWriter> read_buffers_stream_writer_; RequestBufferUsageCallback request_buffer_usage_callback_; - std::unique_ptr<JSONTraceExporter> json_trace_exporter_; + std::unique_ptr<perfetto::trace_processor::TraceProcessorStorage> + trace_processor_; + std::string json_agent_label_filter_; base::OnceCallback<void(bool)> flush_callback_; const mojom::TracingClientPriority tracing_priority_; base::OnceClosure on_disabled_callback_;
diff --git a/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_buffer_android_unittest.cc b/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_buffer_android_unittest.cc index ac969be4..133fc099 100644 --- a/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_buffer_android_unittest.cc +++ b/services/tracing/public/cpp/perfetto/java_heap_profiler/hprof_buffer_android_unittest.cc
@@ -13,30 +13,30 @@ TEST(HprofBufferTest, VerifyBasicGetBytes) { unsigned char file_data[7]{1, 1, 1, 1, 1, 1, 1}; HprofBuffer hprof(file_data, 7); - EXPECT_EQ(hprof.GetOneByte(), (uint32_t)1); - EXPECT_EQ(hprof.GetTwoBytes(), (uint32_t)257); - EXPECT_EQ(hprof.GetFourBytes(), (uint32_t)16843009); + EXPECT_EQ(hprof.GetOneByte(), 1u); + EXPECT_EQ(hprof.GetTwoBytes(), 257u); + EXPECT_EQ(hprof.GetFourBytes(), 16843009u); EXPECT_EQ(hprof.HasRemaining(), false); } TEST(HprofBufferTest, VerifyBasicGetId) { unsigned char file_data[12]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; HprofBuffer hprof(file_data, 12); - EXPECT_EQ(hprof.GetId(), (uint64_t)16843009); + EXPECT_EQ(hprof.GetId(), 16843009u); hprof.set_id_size(8); - EXPECT_EQ(hprof.GetId(), (uint64_t)72340172838076673); + EXPECT_EQ(hprof.GetId(), 72340172838076673u); EXPECT_EQ(hprof.HasRemaining(), false); } TEST(HprofBufferTest, VerifyBasicPositionalMethods) { unsigned char file_data[4]{1, 2, 3, 4}; HprofBuffer hprof(file_data, 4); - EXPECT_EQ(hprof.GetOneByte(), (uint32_t)1); + EXPECT_EQ(hprof.GetOneByte(), 1u); hprof.Skip(2); - EXPECT_EQ(hprof.GetOneByte(), (uint32_t)4); + EXPECT_EQ(hprof.GetOneByte(), 4u); EXPECT_EQ(hprof.HasRemaining(), false); hprof.set_position(1); - EXPECT_EQ(hprof.GetOneByte(), (uint32_t)2); + EXPECT_EQ(hprof.GetOneByte(), 2u); } } // namespace tracing
diff --git a/skia/public/mojom/BUILD.gn b/skia/public/mojom/BUILD.gn index 76b549f..80e7bf1 100644 --- a/skia/public/mojom/BUILD.gn +++ b/skia/public/mojom/BUILD.gn
@@ -4,6 +4,29 @@ import("//mojo/public/tools/bindings/mojom.gni") +# Normally typemap traits sources should be build directly into mojom targets +# via the typemap file. This target is for typemapped mojo_base types whose +# traits are shared between chromium and blink variants. +component("shared_typemap_traits") { + output_name = "skia_shared_typemap_traits" + + sources = [ + "bitmap_skbitmap_mojom_traits.cc", + "bitmap_skbitmap_mojom_traits.h", + "image_info_mojom_traits.cc", + "image_info_mojom_traits.h", + ] + + defines = [ "IS_SKIA_SHARED_TRAITS_IMPL" ] + + public_deps = [ + "//base", + "//mojo/public/cpp/base:shared_typemap_traits", + "//skia", + "//skia/public/mojom:mojom_shared", + ] +} + mojom("mojom") { generate_java = true sources = [
diff --git a/skia/public/mojom/bitmap_skbitmap_mojom_traits.h b/skia/public/mojom/bitmap_skbitmap_mojom_traits.h index 0045fbe7..0f3397f1 100644 --- a/skia/public/mojom/bitmap_skbitmap_mojom_traits.h +++ b/skia/public/mojom/bitmap_skbitmap_mojom_traits.h
@@ -5,11 +5,12 @@ #ifndef SKIA_PUBLIC_MOJOM_BITMAP_SKBITMAP_MOJOM_TRAITS_H_ #define SKIA_PUBLIC_MOJOM_BITMAP_SKBITMAP_MOJOM_TRAITS_H_ +#include "base/component_export.h" #include "base/containers/span.h" #include "mojo/public/cpp/base/big_buffer.h" #include "mojo/public/cpp/base/big_buffer_mojom_traits.h" #include "mojo/public/cpp/bindings/array_traits.h" -#include "skia/public/mojom/bitmap.mojom.h" +#include "skia/public/mojom/bitmap.mojom-shared.h" #include "skia/public/mojom/image_info_mojom_traits.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -17,7 +18,8 @@ // Struct traits to use SkBitmap for skia::mojom::Bitmap in Chrome C++ code. template <> -struct StructTraits<skia::mojom::BitmapDataView, SkBitmap> { +struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) + StructTraits<skia::mojom::BitmapDataView, SkBitmap> { static bool IsNull(const SkBitmap& b); static void SetToNull(SkBitmap* b); static const SkImageInfo& image_info(const SkBitmap& b); @@ -27,7 +29,8 @@ }; template <> -struct StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap> { +struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) + StructTraits<skia::mojom::InlineBitmapDataView, SkBitmap> { static bool IsNull(const SkBitmap& b); static void SetToNull(SkBitmap* b); static const SkImageInfo& image_info(const SkBitmap& b);
diff --git a/skia/public/mojom/image_filter_mojom_traits.cc b/skia/public/mojom/image_filter_mojom_traits.cc deleted file mode 100644 index d70ceda..0000000 --- a/skia/public/mojom/image_filter_mojom_traits.cc +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "skia/public/mojom/image_filter_mojom_traits.h" - -namespace mojo { - -ImageFilterBuffer::ImageFilterBuffer() = default; - -ImageFilterBuffer::ImageFilterBuffer(const ImageFilterBuffer& other) = default; - -ImageFilterBuffer::~ImageFilterBuffer() = default; - -// static -size_t ArrayTraits<ImageFilterBuffer>::GetSize(const ImageFilterBuffer& b) { - return b.data->size(); -} - -// static -uint8_t* ArrayTraits<ImageFilterBuffer>::GetData(ImageFilterBuffer& b) { - return static_cast<uint8_t*>(b.data->writable_data()); -} - -// static -const uint8_t* ArrayTraits<ImageFilterBuffer>::GetData( - const ImageFilterBuffer& b) { - return b.data->bytes(); -} - -// static -uint8_t& ArrayTraits<ImageFilterBuffer>::GetAt(ImageFilterBuffer& b, size_t i) { - return *(static_cast<uint8_t*>(b.data->writable_data()) + i); -} - -// static -const uint8_t& ArrayTraits<ImageFilterBuffer>::GetAt(const ImageFilterBuffer& b, - size_t i) { - return *(b.data->bytes() + i); -} - -// static -bool ArrayTraits<ImageFilterBuffer>::Resize(ImageFilterBuffer& b, size_t size) { - if (b.data) - return size == b.data->size(); - b.data = SkData::MakeUninitialized(size); - return true; -} - -} // namespace mojo
diff --git a/skia/public/mojom/image_info_mojom_traits.h b/skia/public/mojom/image_info_mojom_traits.h index eb8cbbfb..184ccfe 100644 --- a/skia/public/mojom/image_info_mojom_traits.h +++ b/skia/public/mojom/image_info_mojom_traits.h
@@ -7,13 +7,15 @@ #include <vector> -#include "skia/public/mojom/image_info.mojom.h" +#include "base/component_export.h" +#include "skia/public/mojom/image_info.mojom-shared.h" #include "third_party/skia/include/core/SkImageInfo.h" namespace mojo { template <> -struct StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo> { +struct COMPONENT_EXPORT(SKIA_SHARED_TRAITS) + StructTraits<skia::mojom::ImageInfoDataView, SkImageInfo> { static skia::mojom::ColorType color_type(const SkImageInfo& info); static skia::mojom::AlphaType alpha_type(const SkImageInfo& info); static std::vector<uint8_t> serialized_color_space(const SkImageInfo& info);
diff --git a/skia/public/mojom/skbitmap.typemap b/skia/public/mojom/skbitmap.typemap index d4fe455..56b7e94 100644 --- a/skia/public/mojom/skbitmap.typemap +++ b/skia/public/mojom/skbitmap.typemap
@@ -5,14 +5,12 @@ mojom = "//skia/public/mojom/bitmap.mojom" public_headers = [ "//third_party/skia/include/core/SkBitmap.h" ] traits_headers = [ "//skia/public/mojom/bitmap_skbitmap_mojom_traits.h" ] -sources = [ - "//skia/public/mojom/bitmap_skbitmap_mojom_traits.cc", -] deps = [ "//mojo/public/cpp/bindings", ] public_deps = [ "//skia", + "//skia/public/mojom:shared_typemap_traits", ] type_mappings = [ "skia.mojom.Bitmap=::SkBitmap[nullable_is_same_type]",
diff --git a/skia/public/mojom/skbitmap_for_blink.typemap b/skia/public/mojom/skbitmap_for_blink.typemap deleted file mode 100644 index a8f5d8b9..0000000 --- a/skia/public/mojom/skbitmap_for_blink.typemap +++ /dev/null
@@ -1,15 +0,0 @@ -# Copyright 2018 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -mojom = "//skia/public/mojom/bitmap.mojom" -public_headers = [ "//third_party/skia/include/core/SkBitmap.h" ] -traits_headers = [ "//skia/public/mojom/bitmap_skbitmap_mojom_traits.h" ] -deps = [ - "//mojo/public/cpp/bindings", -] -public_deps = [ - "//skia", - "//skia/public/mojom", -] -type_mappings = [ "skia.mojom.Bitmap=::SkBitmap[nullable_is_same_type]" ]
diff --git a/skia/public/mojom/skimageinfo.typemap b/skia/public/mojom/skimageinfo.typemap index b993ca5..a821d95 100644 --- a/skia/public/mojom/skimageinfo.typemap +++ b/skia/public/mojom/skimageinfo.typemap
@@ -5,13 +5,11 @@ mojom = "//skia/public/mojom/image_info.mojom" public_headers = [ "//third_party/skia/include/core/SkImageInfo.h" ] traits_headers = [ "//skia/public/mojom/image_info_mojom_traits.h" ] -sources = [ - "//skia/public/mojom/image_info_mojom_traits.cc", -] deps = [ "//mojo/public/cpp/bindings", ] public_deps = [ "//skia", + "//skia/public/mojom:shared_typemap_traits", ] type_mappings = [ "skia.mojom.ImageInfo=::SkImageInfo" ]
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn index 8cf5f36..7f2c31b 100644 --- a/third_party/blink/public/BUILD.gn +++ b/third_party/blink/public/BUILD.gn
@@ -553,14 +553,6 @@ "grit/blink_resources.h", "blink_resources.pak", ] - grit_flags = [ - "-E", - "blink_core_output_dir=" + - rebase_path(blink_core_output_dir, root_build_dir), - ] - deps = [ - "//third_party/blink/renderer/core:make_minimized_css", - ] } grit("image_resources") {
diff --git a/third_party/blink/public/blink_resources.grd b/third_party/blink/public/blink_resources.grd index 5a55146..c503bc46 100644 --- a/third_party/blink/public/blink_resources.grd +++ b/third_party/blink/public/blink_resources.grd
@@ -8,40 +8,38 @@ </outputs> <release seq="1"> <includes> - <!-- Certain CSS files are processed through minimize_css.py --> - <include name="IDR_UASTYLE_HTML_CSS" file="${cwd}/${blink_core_output_dir}/html.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_QUIRKS_CSS" file="${cwd}/${blink_core_output_dir}/quirks.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_VIEW_SOURCE_CSS" file="${cwd}/${blink_core_output_dir}/view-source.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS" file="${cwd}/${blink_core_output_dir}/android.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_FULLSCREEN_ANDROID_CSS" file="${cwd}/${blink_core_output_dir}/fullscreenAndroid.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS" file="${cwd}/${blink_core_output_dir}/linux.css" type="BINDATA" compress="gzip"/> + <!-- GRIT minimizes all CSS and Javascript --> + <include name="IDR_UASTYLE_HTML_CSS" file="../renderer/core/html/resources/html.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_QUIRKS_CSS" file="../renderer/core/html/resources/quirks.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_VIEW_SOURCE_CSS" file="../renderer/core/css/view-source.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_THEME_CHROMIUM_ANDROID_CSS" file="../renderer/core/html/resources/android.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_FULLSCREEN_ANDROID_CSS" file="../renderer/core/css/fullscreenAndroid.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_THEME_CHROMIUM_LINUX_CSS" file="../renderer/core/html/resources/linux.css" type="BINDATA" compress="gzip"/> <if expr="is_macosx"> <include name="IDR_UASTYLE_THEME_MAC_CSS" file="../renderer/core/html/resources/mac.css" type="BINDATA" compress="gzip"/> </if> - <include name="IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS" file="${cwd}/${blink_core_output_dir}/input_multiple_fields.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_THEME_WIN_CSS" file="${cwd}/${blink_core_output_dir}/win.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_THEME_WIN_QUIRKS_CSS" file="${cwd}/${blink_core_output_dir}/win_quirks.css" type="BINDATA" compress="gzip"/> - <!-- TODO(crbug.com/1015410): Use minimized |controls_refresh.css| with relative urls properly revised --> + <include name="IDR_UASTYLE_THEME_INPUT_MULTIPLE_FIELDS_CSS" file="../renderer/core/html/resources/input_multiple_fields.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_THEME_WIN_CSS" file="../renderer/core/html/resources/win.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_THEME_WIN_QUIRKS_CSS" file="../renderer/core/html/resources/win_quirks.css" type="BINDATA" compress="gzip"/> <include name="IDR_UASTYLE_THEME_CONTROLS_REFRESH_CSS" file="../renderer/core/html/resources/controls_refresh.css" flattenhtml="true" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_THEME_FORCED_COLORS_CSS" file="${cwd}/${blink_core_output_dir}/forced_colors.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_SVG_CSS" file="${cwd}/${blink_core_output_dir}/svg.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_MATHML_CSS" file="${cwd}/${blink_core_output_dir}/mathml.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_FULLSCREEN_CSS" file="${cwd}/${blink_core_output_dir}/fullscreen.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_XHTMLMP_CSS" file="${cwd}/${blink_core_output_dir}/xhtmlmp.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_VIEWPORT_ANDROID_CSS" file="${cwd}/${blink_core_output_dir}/viewportAndroid.css" type="BINDATA" compress="gzip"/> - <include name="IDR_UASTYLE_VIEWPORT_TELEVISION_CSS" file="${cwd}/${blink_core_output_dir}/viewportTelevision.css" type="BINDATA" compress="gzip"/> - + <include name="IDR_UASTYLE_THEME_FORCED_COLORS_CSS" file="../renderer/core/html/resources/forced_colors.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_SVG_CSS" file="../renderer/core/css/svg.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_MATHML_CSS" file="../renderer/core/css/mathml.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_FULLSCREEN_CSS" file="../renderer/core/css/fullscreen.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_XHTMLMP_CSS" file="../renderer/core/css/xhtmlmp.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_VIEWPORT_ANDROID_CSS" file="../renderer/core/css/viewportAndroid.css" type="BINDATA" compress="gzip"/> + <include name="IDR_UASTYLE_VIEWPORT_TELEVISION_CSS" file="../renderer/core/css/viewportTelevision.css" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_COMMON_JS" file="../renderer/core/inspector/inspect_tool_common.js" type="BINDATA" compress="gzip"/> - <include name="IDR_INSPECT_TOOL_COMMON_CSS" file="${cwd}/${blink_core_output_dir}/inspect_tool_common.css" type="BINDATA" compress="gzip"/> + <include name="IDR_INSPECT_TOOL_COMMON_CSS" file="../renderer/core/inspector/inspect_tool_common.css" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_DISTANCES_HTML" file="../renderer/core/inspector/inspect_tool_distances.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_HIGHLIGHT_HTML" file="../renderer/core/inspector/inspect_tool_highlight.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_PAUSED_HTML" file="../renderer/core/inspector/inspect_tool_paused.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_VIEWPORT_SIZE_HTML" file="../renderer/core/inspector/inspect_tool_viewport_size.html" type="BINDATA" compress="gzip"/> <include name="IDR_INSPECT_TOOL_SCREENSHOT_HTML" file="../renderer/core/inspector/inspect_tool_screenshot.html" type="BINDATA" compress="gzip"/> - <include name="IDR_DOCUMENTXMLTREEVIEWER_CSS" file="${cwd}/${blink_core_output_dir}/DocumentXMLTreeViewer.css" type="BINDATA" compress="gzip"/> + <include name="IDR_DOCUMENTXMLTREEVIEWER_CSS" file="../renderer/core/xml/DocumentXMLTreeViewer.css" type="BINDATA" compress="gzip"/> <include name="IDR_DOCUMENTXMLTREEVIEWER_JS" file="../renderer/core/xml/DocumentXMLTreeViewer.js" type="BINDATA" compress="gzip"/> <include name="IDR_VALIDATION_BUBBLE_ICON" file="../renderer/core/html/forms/resources/input_alert.svg" type="BINDATA" compress="gzip"/> - <include name="IDR_VALIDATION_BUBBLE_CSS" file="${cwd}/${blink_core_output_dir}/validation_bubble.css" type="BINDATA" compress="gzip"/> + <include name="IDR_VALIDATION_BUBBLE_CSS" file="../renderer/core/html/forms/resources/validation_bubble.css" type="BINDATA" compress="gzip"/> <if expr="not is_android"> <include name="IDR_PICKER_COMMON_JS" file="../renderer/core/html/forms/resources/pickerCommon.js" type="BINDATA" compress="gzip"/> <include name="IDR_PICKER_COMMON_CSS" file="../renderer/core/html/forms/resources/pickerCommon.css" type="BINDATA" compress="gzip"/> @@ -64,10 +62,8 @@ <include name="IDR_LIST_PICKER_JS" file="../renderer/core/html/forms/resources/listPicker.js" type="BINDATA" compress="gzip"/> </if> <include name="IDR_AUDIO_SPATIALIZATION_COMPOSITE" file="../renderer/platform/audio/resources/Composite.flac" type="BINDATA"/> - <!-- Layered API scripts. --> <part file="../renderer/core/script/resources/layered_api/resources.grdp" /> - </includes> </release> </grit>
diff --git a/third_party/blink/public/blink_typemaps.gni b/third_party/blink/public/blink_typemaps.gni index 46e49485..1e1fc204 100644 --- a/third_party/blink/public/blink_typemaps.gni +++ b/third_party/blink/public/blink_typemaps.gni
@@ -23,7 +23,6 @@ "//services/viz/public/cpp/compositing/returned_resource.typemap", "//services/viz/public/cpp/compositing/surface_id.typemap", "//services/viz/public/cpp/compositing/surface_info.typemap", - "//skia/public/mojom/skbitmap_for_blink.typemap", "//ui/display/mojom/display_rotation_for_blink.typemap", "//ui/gfx/mojom/gpu_fence_handle_for_blink.typemap", ]
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn index 1dbf29d1..64512327 100644 --- a/third_party/blink/public/common/BUILD.gn +++ b/third_party/blink/public/common/BUILD.gn
@@ -144,6 +144,7 @@ public_deps = [ "//services/network/public/cpp:cpp", "//skia", + "//skia/public/mojom:shared_typemap_traits", "//third_party/blink/public/mojom:mojom_modules_headers", "//third_party/blink/public/mojom:web_bluetooth_mojo_bindings_headers", ]
diff --git a/third_party/blink/public/platform/DEPS b/third_party/blink/public/platform/DEPS index 5b3c791..9c2d9a0 100644 --- a/third_party/blink/public/platform/DEPS +++ b/third_party/blink/public/platform/DEPS
@@ -26,6 +26,7 @@ "+media/base/audio_capturer_source.h", "+media/base/audio_renderer_sink.h", "+media/base/eme_constants.h", + "+media/base/video_frame.h", "+media/base/video_transformation.h", "+mojo/public", "+net/cert",
diff --git a/third_party/blink/public/platform/web_media_player.h b/third_party/blink/public/platform/web_media_player.h index b4760b4..d8624b50 100644 --- a/third_party/blink/public/platform/web_media_player.h +++ b/third_party/blink/public/platform/web_media_player.h
@@ -430,6 +430,12 @@ // empty GURL, which will be interpreted as "use the original URL". virtual GURL GetSrcAfterRedirects() { return GURL(); } + // Register a request to be notified the next time a video frame is presented + // to the compositor. The video frame and its metadata will be surfaced via + // WebMediaPlayerClient::OnRequestAnimationFrame(). + // TODO(https://crbug.com/1022186): Add pointer to spec. + virtual void RequestAnimationFrame() {} + virtual base::WeakPtr<WebMediaPlayer> AsWeakPtr() = 0; };
diff --git a/third_party/blink/public/platform/web_media_player_client.h b/third_party/blink/public/platform/web_media_player_client.h index 850b079..babc1ec 100644 --- a/third_party/blink/public/platform/web_media_player_client.h +++ b/third_party/blink/public/platform/web_media_player_client.h
@@ -31,6 +31,8 @@ #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_PLAYER_CLIENT_H_ #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_WEB_MEDIA_PLAYER_CLIENT_H_ +#include "base/time/time.h" +#include "media/base/video_frame.h" #include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_media_player.h" #include "ui/gfx/color_space.h" @@ -177,6 +179,15 @@ // - Natural Size. virtual void OnPictureInPictureStateChange() = 0; + // Called when a video frame has been presented to the compositor, after a + // request was initiated via WebMediaPlayer::RequestAnimationFrame(). + // TODO(https://crbug.com/1022186): Add pointer to spec. + virtual void OnRequestAnimationFrame( + base::TimeTicks presentation_time, + base::TimeTicks expected_presentation_time, + uint32_t presented_frames_counter, + const media::VideoFrame& presented_frame) {} + struct Features { WebString id; WebString width;
diff --git a/third_party/blink/renderer/bindings/modules/v8/generated.gni b/third_party/blink/renderer/bindings/modules/v8/generated.gni index f4467ba5..a215c14 100644 --- a/third_party/blink/renderer/bindings/modules/v8/generated.gni +++ b/third_party/blink/renderer/bindings/modules/v8/generated.gni
@@ -119,6 +119,8 @@ "$bindings_modules_v8_output_dir/v8_decode_success_callback.h", "$bindings_modules_v8_output_dir/v8_idb_observer_callback.cc", "$bindings_modules_v8_output_dir/v8_idb_observer_callback.h", + "$bindings_modules_v8_output_dir/v8_launch_consumer.cc", + "$bindings_modules_v8_output_dir/v8_launch_consumer.h", "$bindings_modules_v8_output_dir/v8_lock_granted_callback.cc", "$bindings_modules_v8_output_dir/v8_lock_granted_callback.h", "$bindings_modules_v8_output_dir/v8_media_session_action_handler.cc",
diff --git a/third_party/blink/renderer/build/scripts/minimize_css.py b/third_party/blink/renderer/build/scripts/minimize_css.py deleted file mode 100755 index b5d6630..0000000 --- a/third_party/blink/renderer/build/scripts/minimize_css.py +++ /dev/null
@@ -1,121 +0,0 @@ -#!/usr/bin/env python -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -import functools -import os.path -import re -import sys - -import in_generator - - -class CSSMinimizer(object): - - INITIAL = 0 - MAYBE_COMMENT_START = 1 - INSIDE_COMMENT = 2 - MAYBE_COMMENT_END = 3 - INSIDE_SINGLE_QUOTE = 4 - INSIDE_SINGLE_QUOTE_ESCAPE = 5 - INSIDE_DOUBLE_QUOTE = 6 - INSIDE_DOUBLE_QUOTE_ESCAPE = 7 - - def __init__(self): - self._output = '' - self._codeblock = '' - - def flush_codeblock(self): - stripped = re.sub(r"\s+", ' ', self._codeblock) - stripped = re.sub(r";?\s*(?P<op>[{};])\s*", r'\g<op>', stripped) - self._output += stripped - self._codeblock = '' - - def parse(self, content): - state = self.INITIAL - for char in content: - if state == self.INITIAL: - if char == '/': - state = self.MAYBE_COMMENT_START - elif char == "'": - self.flush_codeblock() - self._output += char - state = self.INSIDE_SINGLE_QUOTE - elif char == '"': - self.flush_codeblock() - self._output += char - state = self.INSIDE_DOUBLE_QUOTE - else: - self._codeblock += char - elif state == self.MAYBE_COMMENT_START: - if char == '*': - self.flush_codeblock() - state = self.INSIDE_COMMENT - else: - self._codeblock += '/' + char - state = self.INITIAL - elif state == self.INSIDE_COMMENT: - if char == '*': - state = self.MAYBE_COMMENT_END - else: - pass - elif state == self.MAYBE_COMMENT_END: - if char == '/': - state = self.INITIAL - else: - state = self.INSIDE_COMMENT - elif state == self.INSIDE_SINGLE_QUOTE: - if char == '\\': - self._output += char - state = self.INSIDE_SINGLE_QUOTE_ESCAPE - elif char == "'": - self._output += char - state = self.INITIAL - else: - self._output += char - elif state == self.INSIDE_SINGLE_QUOTE_ESCAPE: - self._output += char - state = self.INSIDE_SINGLE_QUOTE - elif state == self.INSIDE_DOUBLE_QUOTE: - if char == '\\': - self._output += char - state = self.INSIDE_DOUBLE_QUOTE_ESCAPE - elif char == '"': - self._output += char - state = self.INITIAL - else: - self._output += char - elif state == self.INSIDE_DOUBLE_QUOTE_ESCAPE: - self._output += char - state = self.INSIDE_DOUBLE_QUOTE - - self.flush_codeblock() - self._output = self._output.strip() - return self._output - - @classmethod - def minimize_css(cls, content): - minimizer = CSSMinimizer() - return minimizer.parse(content) - - -class CSSMinimizerWriter(in_generator.GenericWriter): - - def __init__(self, in_file_paths): - super(CSSMinimizerWriter, self).__init__(in_file_paths) - - self._outputs = {} - for in_file_path in in_file_paths: - out_path = os.path.basename(in_file_path) - self._outputs[out_path] = functools.partial(self.generate_implementation, in_file_path) - - def generate_implementation(self, in_file_path): - content = '' - with open(os.path.abspath(in_file_path)) as in_file: - content = in_file.read() - return CSSMinimizer.minimize_css(content) - - -if __name__ == '__main__': - in_generator.Maker(CSSMinimizerWriter).main(sys.argv)
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index b5d9b79f..4d1144d 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -807,61 +807,6 @@ # One-off scripts -------------------------------------------------------------- -action("make_minimized_css") { - script = "../build/scripts/minimize_css.py" - - inputs = [ - "css/fullscreen.css", - "css/fullscreenAndroid.css", - "css/mathml.css", - "css/svg.css", - "css/view-source.css", - "css/viewportAndroid.css", - "css/viewportTelevision.css", - "css/xhtmlmp.css", - "html/forms/resources/validation_bubble.css", - "html/resources/android.css", - "html/resources/forced_colors.css", - "html/resources/html.css", - "html/resources/input_multiple_fields.css", - "html/resources/linux.css", - "html/resources/quirks.css", - "html/resources/win.css", - "html/resources/win_quirks.css", - "inspector/inspect_tool_common.css", - "xml/DocumentXMLTreeViewer.css", - ] - outputs = [ - "$blink_core_output_dir/fullscreen.css", - "$blink_core_output_dir/fullscreenAndroid.css", - "$blink_core_output_dir/mathml.css", - "$blink_core_output_dir/svg.css", - "$blink_core_output_dir/view-source.css", - "$blink_core_output_dir/viewportAndroid.css", - "$blink_core_output_dir/viewportTelevision.css", - "$blink_core_output_dir/xhtmlmp.css", - "$blink_core_output_dir/validation_bubble.css", - "$blink_core_output_dir/android.css", - "$blink_core_output_dir/forced_colors.css", - "$blink_core_output_dir/html.css", - "$blink_core_output_dir/input_multiple_fields.css", - "$blink_core_output_dir/linux.css", - "$blink_core_output_dir/quirks.css", - "$blink_core_output_dir/win.css", - "$blink_core_output_dir/win_quirks.css", - "$blink_core_output_dir/inspect_tool_common.css", - "$blink_core_output_dir/DocumentXMLTreeViewer.css", - ] - - args = [ - "--output_dir", - rel_blink_core_gen_dir, - ] - args += rebase_path(inputs, root_build_dir) - - deps = make_core_generated_deps -} - action("make_core_generated_html_entity_table") { visibility = [] # Allow re-assignment of list. visibility = [ ":*" ]
diff --git a/third_party/blink/renderer/core/frame/local_frame_view.cc b/third_party/blink/renderer/core/frame/local_frame_view.cc index 22243f5c..a716d44c 100644 --- a/third_party/blink/renderer/core/frame/local_frame_view.cc +++ b/third_party/blink/renderer/core/frame/local_frame_view.cc
@@ -609,6 +609,17 @@ void LocalFrameView::LayoutFromRootObject(LayoutObject& root) { LayoutState layout_state(root); + // Since we are starting layout from an arbitrary node, we need to notify all + // possible scroll anchors above us, as they aren't notified during layout. + for (auto* ancestor = root.Container(); ancestor; + ancestor = ancestor->Container()) { + if (ancestor->HasOverflowClip() && ancestor->IsLayoutBlock()) { + auto* scrollable_area = + ToLayoutBoxModelObject(ancestor)->GetScrollableArea(); + DCHECK(scrollable_area); + scrollable_area->GetScrollAnchor()->NotifyBeforeLayout(); + } + } root.UpdateLayout(); }
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc index c8454e99..089cd25 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -1287,14 +1287,11 @@ script_state, ImageBitmap::Create(this, crop_rect, options)); } -void HTMLCanvasElement::SetOffscreenCanvasFrame( +void HTMLCanvasElement::SetOffscreenCanvasResource( scoped_refptr<CanvasResource> image, - base::WeakPtr<CanvasResourceDispatcher> dispatcher, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, unsigned resource_id) { - OffscreenCanvasPlaceholder::SetOffscreenCanvasFrame( - std::move(image), std::move(dispatcher), std::move(task_runner), - resource_id); + OffscreenCanvasPlaceholder::SetOffscreenCanvasResource(std::move(image), + resource_id); SetSize(OffscreenCanvasFrame()->Size()); NotifyListenersCanvasChanged(); }
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h index 978e4fd..e765067 100644 --- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h +++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -237,10 +237,8 @@ const ImageBitmapOptions*) override; // OffscreenCanvasPlaceholder implementation. - void SetOffscreenCanvasFrame(scoped_refptr<CanvasResource>, - base::WeakPtr<CanvasResourceDispatcher>, - scoped_refptr<base::SingleThreadTaskRunner>, - unsigned resource_id) override; + void SetOffscreenCanvasResource(scoped_refptr<CanvasResource>, + unsigned resource_id) override; void Trace(Visitor*) override; void SetResourceProviderForTesting(std::unique_ptr<CanvasResourceProvider>,
diff --git a/third_party/blink/renderer/core/html/forms/file_chooser.cc b/third_party/blink/renderer/core/html/forms/file_chooser.cc index 60dbf7f..cbf940f5 100644 --- a/third_party/blink/renderer/core/html/forms/file_chooser.cc +++ b/third_party/blink/renderer/core/html/forms/file_chooser.cc
@@ -160,6 +160,8 @@ chrome_client_impl_->UnregisterPopupOpeningObserver(client_); } + if (client_) + client_->DisconnectFileChooser(); Release(); }
diff --git a/third_party/blink/renderer/core/html/forms/file_chooser.h b/third_party/blink/renderer/core/html/forms/file_chooser.h index a98154b..b79759e 100644 --- a/third_party/blink/renderer/core/html/forms/file_chooser.h +++ b/third_party/blink/renderer/core/html/forms/file_chooser.h
@@ -60,13 +60,14 @@ // DisconnectFileChooser(). FileChooser* FileChooserOrNull() const { return chooser_.get(); } - protected: - FileChooser* NewFileChooser(const mojom::blink::FileChooserParams&); - bool HasConnectedFileChooser() const { return chooser_.get(); } - // This should be called if a user chose files or cancel the dialog. void DisconnectFileChooser(); + FileChooser* NewFileChooser(const mojom::blink::FileChooserParams&); + + protected: + bool HasConnectedFileChooser() const { return chooser_.get(); } + private: scoped_refptr<FileChooser> chooser_; }; @@ -96,7 +97,7 @@ // mojom::blink::FileChooser callback void DidChooseFiles(mojom::blink::FileChooserResultPtr result); - WeakPersistent<FileChooserClient> client_; + Persistent<FileChooserClient> client_; mojom::blink::FileChooserParamsPtr params_; Persistent<ChromeClientImpl> chrome_client_impl_; mojo::Remote<mojom::blink::FileChooser> file_chooser_;
diff --git a/third_party/blink/renderer/core/html/resources/controls_refresh.css b/third_party/blink/renderer/core/html/resources/controls_refresh.css index 98b3f6c..5f1e0e3b 100644 --- a/third_party/blink/renderer/core/html/resources/controls_refresh.css +++ b/third_party/blink/renderer/core/html/resources/controls_refresh.css
@@ -168,16 +168,6 @@ border-radius: 2px; } -/* These options only apply to in-page 'multiple' select elements. - The options in the popup are handled in listPicker.css */ -select:-internal-list-box option, select:-internal-list-box optgroup { - padding: 0 3px; -} - -select:-internal-list-box option { - border-radius: 2px; -} - select:-internal-list-box option:hover { background-color: #f3f3f3; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc index 22bca26..7a1cc31 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -222,8 +222,7 @@ } space_builder.SetAvailableSize(content_box_size_); - space_builder.SetPercentageResolutionSize(CalculateChildPercentageSize( - ConstraintSpace(), Node(), content_box_size_)); + space_builder.SetPercentageResolutionSize(child_percentage_size_); return space_builder.ToConstraintSpace(); } @@ -500,6 +499,8 @@ border_box_size_ = container_builder_.InitialBorderBoxSize(); content_box_size_ = ShrinkAvailableSize(border_box_size_, border_scrollbar_padding_); + child_percentage_size_ = CalculateChildPercentageSize( + ConstraintSpace(), Node(), content_box_size_); const LayoutUnit line_break_length = MainAxisContentExtent(LayoutUnit::Max()); algorithm_.emplace(&Style(), line_break_length); @@ -562,11 +563,7 @@ } space_builder.SetAvailableSize(available_size); - // CalculateChildPercentageSize probably has no effect here: - // content_box_size_ would already be indefinite without - // CalculateChildPercentageSize checking IsFixedBlockSizeIndefinite. - space_builder.SetPercentageResolutionSize(CalculateChildPercentageSize( - ConstraintSpace(), Node(), content_box_size_)); + space_builder.SetPercentageResolutionSize(child_percentage_size_); // https://drafts.csswg.org/css-flexbox/#algo-cross-item // Determine the hypothetical cross size of each item by performing layout @@ -626,8 +623,7 @@ } } space_builder.SetAvailableSize(available_size); - space_builder.SetPercentageResolutionSize(CalculateChildPercentageSize( - ConstraintSpace(), Node(), content_box_size_)); + space_builder.SetPercentageResolutionSize(child_percentage_size_); space_builder.SetIsFixedInlineSize(true); space_builder.SetIsFixedBlockSize(true); NGConstraintSpace child_space = space_builder.ToConstraintSpace();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h index 6290436..16f6aaa0 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h +++ b/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
@@ -73,6 +73,7 @@ // ComputeMinMaxSize() or anything it calls. LogicalSize border_box_size_; LogicalSize content_box_size_; + LogicalSize child_percentage_size_; base::Optional<FlexLayoutAlgorithm> algorithm_; };
diff --git a/third_party/blink/renderer/core/layout/ng/table/interface_casting.h b/third_party/blink/renderer/core/layout/ng/table/interface_casting.h index dab99df1..c74cecc 100644 --- a/third_party/blink/renderer/core/layout/ng/table/interface_casting.h +++ b/third_party/blink/renderer/core/layout/ng/table/interface_casting.h
@@ -69,7 +69,8 @@ template <typename Derived, typename Base> const Derived* ToInterface(const Base* from) { - SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(*from)); + if (from) + SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(*from)); return from ? &InterfaceDowncastTraits<Derived>::ConvertFrom(*from) : nullptr; } @@ -83,7 +84,8 @@ template <typename Derived, typename Base> Derived* ToInterface(Base* from) { - SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(*from)); + if (from) + SECURITY_DCHECK(InterfaceDowncastTraits<Derived>::AllowFrom(*from)); // const_cast is safe because from is not const. return from ? const_cast<Derived*>( &InterfaceDowncastTraits<Derived>::ConvertFrom(*from))
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc index b90c058..2a85555 100644 --- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc +++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -31,6 +31,7 @@ #include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" #include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include "third_party/skia/include/core/SkFilterQuality.h" #include "third_party/skia/include/core/SkSurface.h" namespace blink { @@ -105,6 +106,9 @@ if (animation_frame_provider) animation_frame_provider->RegisterOffscreenCanvas(this); } + if (frame_dispatcher_) { + frame_dispatcher_->SetPlaceholderCanvasDispatcher(placeholder_canvas_id_); + } } void OffscreenCanvas::setWidth(unsigned width) { @@ -313,6 +317,9 @@ // throughout the lifetime of this OffscreenCanvas. frame_dispatcher_ = std::make_unique<CanvasResourceDispatcher>( this, client_id_, sink_id_, placeholder_canvas_id_, size_); + + if (HasPlaceholderCanvas()) + frame_dispatcher_->SetPlaceholderCanvasDispatcher(placeholder_canvas_id_); } return frame_dispatcher_.get(); } @@ -411,6 +418,16 @@ return PushFrameIfNeeded(); } +void OffscreenCanvas::SetFilterQualityInResource( + SkFilterQuality filter_quality) { + if (filter_quality_ == filter_quality) + return; + + filter_quality_ = filter_quality; + if (ResourceProvider()) + GetOrCreateResourceProvider()->SetFilterQuality(filter_quality); +} + bool OffscreenCanvas::PushFrameIfNeeded() { if (needs_push_frame_ && context_) { return context_->PushFrame();
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h index c198d42..0ea8924 100644 --- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h +++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -63,6 +63,7 @@ // CanvasResourceDispatcherClient bool BeginFrame() override; + void SetFilterQualityInResource(SkFilterQuality filter_quality) override; // API Methods ImageBitmap* transferToImageBitmap(ScriptState*, ExceptionState&);
diff --git a/third_party/blink/renderer/core/page/chrome_client.h b/third_party/blink/renderer/core/page/chrome_client.h index 544294e..7ab1fb7 100644 --- a/third_party/blink/renderer/core/page/chrome_client.h +++ b/third_party/blink/renderer/core/page/chrome_client.h
@@ -482,6 +482,8 @@ virtual void DidUpdateTextAutosizerPageInfo(const WebTextAutosizerPageInfo&) { } + virtual void DocumentDetached(Document&) {} + protected: ChromeClient() = default;
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.cc b/third_party/blink/renderer/core/page/chrome_client_impl.cc index b04f661..19717a1 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl.cc
@@ -1280,4 +1280,11 @@ web_view_->Client()->DidUpdateTextAutosizerPageInfo(page_info); } +void ChromeClientImpl::DocumentDetached(Document& document) { + for (auto& it : file_chooser_queue_) { + if (it->FrameOrNull() == document.GetFrame()) + it->DisconnectClient(); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl.h b/third_party/blink/renderer/core/page/chrome_client_impl.h index 93307ad8..9681f81 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl.h +++ b/third_party/blink/renderer/core/page/chrome_client_impl.h
@@ -268,6 +268,8 @@ void DidUpdateTextAutosizerPageInfo(const WebTextAutosizerPageInfo&) override; + void DocumentDetached(Document&) override; + private: bool IsChromeClientImpl() const override { return true; }
diff --git a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc index 127fcc5..75815d3 100644 --- a/third_party/blink/renderer/core/page/chrome_client_impl_test.cc +++ b/third_party/blink/renderer/core/page/chrome_client_impl_test.cc
@@ -274,8 +274,8 @@ auto* client2 = MakeGarbageCollected<MockFileChooserClient>(frame); mojom::blink::FileChooserParams params; params.title = g_empty_string; - scoped_refptr<FileChooser> chooser1 = FileChooser::Create(client1, params); - scoped_refptr<FileChooser> chooser2 = FileChooser::Create(client2, params); + scoped_refptr<FileChooser> chooser1 = client1->NewFileChooser(params); + scoped_refptr<FileChooser> chooser2 = client2->NewFileChooser(params); chrome_client_impl_->OpenFileChooser(frame, chooser1); chrome_client_impl_->OpenFileChooser(frame, chooser2);
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc index 9060d1a..a0a4133 100644 --- a/third_party/blink/renderer/core/page/page.cc +++ b/third_party/blink/renderer/core/page/page.cc
@@ -318,6 +318,8 @@ if (agent_metrics_collector_) agent_metrics_collector_->DidDetachDocument(*document); + + GetChromeClient().DocumentDetached(*document); } bool Page::OpenedByDOM() const {
diff --git a/third_party/blink/renderer/core/paint/html_canvas_painter.cc b/third_party/blink/renderer/core/paint/html_canvas_painter.cc index 05c8f34a..41ad9be 100644 --- a/third_party/blink/renderer/core/paint/html_canvas_painter.cc +++ b/third_party/blink/renderer/core/paint/html_canvas_painter.cc
@@ -37,6 +37,8 @@ paint_rect.Move(paint_offset); auto* canvas = To<HTMLCanvasElement>(layout_html_canvas_.GetNode()); + if (canvas->IsOffscreenCanvasRegistered()) + canvas->UpdateOffscreenCanvasFilterQuality(canvas->FilterQuality()); if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (auto* layer = canvas->ContentsCcLayer()) {
diff --git a/third_party/blink/renderer/core/timing/performance.cc b/third_party/blink/renderer/core/timing/performance.cc index 71a4412..89afeba 100644 --- a/third_party/blink/renderer/core/timing/performance.cc +++ b/third_party/blink/renderer/core/timing/performance.cc
@@ -70,6 +70,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/resource_load_timing.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_timing_info.h" +#include "third_party/blink/renderer/platform/network/http_parsers.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/weborigin/security_origin.h" #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h" @@ -369,29 +370,22 @@ if (timing_allow_origin_string.IsEmpty()) return false; - // The condition below if only needed for use-counting purposes. - if (timing_allow_origin_string == "*") { - UseCounter::Count(context, WebFeature::kStarInTimingAllowOrigin); - return true; - } - - // TODO(yoav): Use CommaDelimitedHeaderSet instead of this one-off parsing - // algorithm. const String& security_origin = initiator_security_origin.ToString(); - Vector<String> timing_allow_origins; - timing_allow_origin_string.GetString().Split(',', timing_allow_origins); - if (timing_allow_origins.size() > 1) { - UseCounter::Count(context, WebFeature::kMultipleOriginsInTimingAllowOrigin); - } else if (timing_allow_origins.size() == 1 && - timing_allow_origin_string != "*") { - UseCounter::Count(context, WebFeature::kSingleOriginInTimingAllowOrigin); - } - for (const String& allow_origin : timing_allow_origins) { - const String allow_origin_stripped = allow_origin.StripWhiteSpace(); - if (allow_origin_stripped == security_origin || - allow_origin_stripped == "*") { + CommaDelimitedHeaderSet tao_headers; + ParseCommaDelimitedHeader(timing_allow_origin_string, tao_headers); + if (tao_headers.size() == 1u) { + if (*tao_headers.begin() == "*") { + UseCounter::Count(context, WebFeature::kStarInTimingAllowOrigin); return true; + } else { + UseCounter::Count(context, WebFeature::kSingleOriginInTimingAllowOrigin); } + } else if (tao_headers.size() > 1u) { + UseCounter::Count(context, WebFeature::kMultipleOriginsInTimingAllowOrigin); + } + for (const String& header : tao_headers) { + if (header == "*" || header == security_origin) + return true; } return false;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc index 45c76003..d3e3af9 100644 --- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc +++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -287,9 +287,14 @@ if (HasGlobalARIAAttribute()) return kIncludeObject; - if (IsImage()) - return kIncludeObject; - + bool has_non_empty_alt_attribute = !GetAttribute(kAltAttr).IsEmpty(); + if (IsImage()) { + if (has_non_empty_alt_attribute || GetAttribute(kAltAttr).IsNull()) + return kIncludeObject; + else if (ignored_reasons) + ignored_reasons->push_back(IgnoredReason(kAXEmptyAlt)); + return kIgnoreObject; + } // Using the title or accessibility description (so we // check if there's some kind of accessible name for the element) // to decide an element's visibility is not as definitive as @@ -298,8 +303,8 @@ // These checks are simplified in the interest of execution speed; // for example, any element having an alt attribute will make it // not ignored, rather than just images. - if (HasAriaAttribute(GetElement()) || !GetAttribute(kAltAttr).IsEmpty() || - !GetAttribute(kTitleAttr).IsEmpty()) + if (HasAriaAttribute(GetElement()) || !GetAttribute(kTitleAttr).IsEmpty() || + has_non_empty_alt_attribute) return kIncludeObject; // <span> tags are inline tags and not meant to convey information if they
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc index 66271ef4c..3593258de 100644 --- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc +++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
@@ -77,8 +77,8 @@ offscreen_canvas->AllowHighPerformancePowerPreference(); DOMNodeId canvas_id = DOMNodeIds::IdForNode(&canvas); - offscreen_canvas->SetPlaceholderCanvasId(canvas_id); canvas.RegisterPlaceholderCanvas(static_cast<int>(canvas_id)); + offscreen_canvas->SetPlaceholderCanvasId(canvas_id); SurfaceLayerBridge* bridge = canvas.SurfaceLayerBridge(); if (bridge) {
diff --git a/third_party/blink/renderer/modules/launch/BUILD.gn b/third_party/blink/renderer/modules/launch/BUILD.gn index e722c899..86215df8 100644 --- a/third_party/blink/renderer/modules/launch/BUILD.gn +++ b/third_party/blink/renderer/modules/launch/BUILD.gn
@@ -6,10 +6,12 @@ blink_modules_sources("launch") { sources = [ - "dom_window_launch_params.cc", - "dom_window_launch_params.h", + "dom_window_launch_queue.cc", + "dom_window_launch_queue.h", "launch_params.cc", "launch_params.h", + "launch_queue.cc", + "launch_queue.h", "web_launch_service_impl.cc", "web_launch_service_impl.h", ]
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_params.cc b/third_party/blink/renderer/modules/launch/dom_window_launch_params.cc deleted file mode 100644 index 1fbb94f..0000000 --- a/third_party/blink/renderer/modules/launch/dom_window_launch_params.cc +++ /dev/null
@@ -1,50 +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. - -#include "third_party/blink/renderer/modules/launch/dom_window_launch_params.h" - -#include "third_party/blink/renderer/core/frame/local_dom_window.h" -#include "third_party/blink/renderer/modules/launch/launch_params.h" -#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h" -#include "third_party/blink/renderer/platform/heap/heap.h" -#include "third_party/blink/renderer/platform/heap/visitor.h" -#include "third_party/blink/renderer/platform/wtf/functional.h" - -namespace blink { - -const char DOMWindowLaunchParams::kSupplementName[] = "DOMWindowLaunchParams"; - -DOMWindowLaunchParams::DOMWindowLaunchParams() - : launch_params_(MakeGarbageCollected<LaunchParams>()) {} -DOMWindowLaunchParams::~DOMWindowLaunchParams() = default; - -Member<LaunchParams> DOMWindowLaunchParams::launchParams( - LocalDOMWindow& window) { - return FromState(&window)->launch_params_; -} - -void DOMWindowLaunchParams::UpdateLaunchFiles( - LocalDOMWindow* window, - HeapVector<Member<NativeFileSystemHandle>> files) { - FromState(window)->launch_params_->SetFiles(std::move(files)); -} - -void DOMWindowLaunchParams::Trace(blink::Visitor* visitor) { - visitor->Trace(launch_params_); - Supplement<LocalDOMWindow>::Trace(visitor); -} - -// static -DOMWindowLaunchParams* DOMWindowLaunchParams::FromState( - LocalDOMWindow* window) { - DOMWindowLaunchParams* supplement = - Supplement<LocalDOMWindow>::From<DOMWindowLaunchParams>(window); - if (!supplement) { - supplement = MakeGarbageCollected<DOMWindowLaunchParams>(); - ProvideTo(*window, supplement); - } - return supplement; -} - -} // namespace blink
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc new file mode 100644 index 0000000..a7ef74a --- /dev/null +++ b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.cc
@@ -0,0 +1,49 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/modules/launch/dom_window_launch_queue.h" + +#include "third_party/blink/renderer/core/frame/local_dom_window.h" +#include "third_party/blink/renderer/modules/launch/launch_params.h" +#include "third_party/blink/renderer/modules/native_file_system/native_file_system_handle.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" +#include "third_party/blink/renderer/platform/wtf/functional.h" + +namespace blink { + +const char DOMWindowLaunchQueue::kSupplementName[] = "DOMWindowLaunchQueue"; + +DOMWindowLaunchQueue::DOMWindowLaunchQueue() + : launch_queue_(MakeGarbageCollected<LaunchQueue>()) {} +DOMWindowLaunchQueue::~DOMWindowLaunchQueue() = default; + +Member<LaunchQueue> DOMWindowLaunchQueue::launchQueue(LocalDOMWindow& window) { + return FromState(&window)->launch_queue_; +} + +void DOMWindowLaunchQueue::UpdateLaunchFiles( + LocalDOMWindow* window, + HeapVector<Member<NativeFileSystemHandle>> files) { + FromState(window)->launch_queue_->Enqueue( + MakeGarbageCollected<LaunchParams>(std::move(files))); +} + +void DOMWindowLaunchQueue::Trace(blink::Visitor* visitor) { + visitor->Trace(launch_queue_); + Supplement<LocalDOMWindow>::Trace(visitor); +} + +// static +DOMWindowLaunchQueue* DOMWindowLaunchQueue::FromState(LocalDOMWindow* window) { + DOMWindowLaunchQueue* supplement = + Supplement<LocalDOMWindow>::From<DOMWindowLaunchQueue>(window); + if (!supplement) { + supplement = MakeGarbageCollected<DOMWindowLaunchQueue>(); + ProvideTo(*window, supplement); + } + return supplement; +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_params.h b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h similarity index 72% rename from third_party/blink/renderer/modules/launch/dom_window_launch_params.h rename to third_party/blink/renderer/modules/launch/dom_window_launch_queue.h index d20cfa4..4990a78e 100644 --- a/third_party/blink/renderer/modules/launch/dom_window_launch_params.h +++ b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.h
@@ -2,10 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_DOM_WINDOW_LAUNCH_PARAMS_H_ -#define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_DOM_WINDOW_LAUNCH_PARAMS_H_ +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_DOM_WINDOW_LAUNCH_QUEUE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_DOM_WINDOW_LAUNCH_QUEUE_H_ #include "third_party/blink/renderer/modules/launch/launch_params.h" +#include "third_party/blink/renderer/modules/launch/launch_queue.h" #include "third_party/blink/renderer/platform/heap/garbage_collected.h" #include "third_party/blink/renderer/platform/heap/handle.h" #include "third_party/blink/renderer/platform/heap/heap.h" @@ -19,19 +20,19 @@ class LocalDOMWindow; class Visitor; -class DOMWindowLaunchParams final - : public GarbageCollected<DOMWindowLaunchParams>, +class DOMWindowLaunchQueue final + : public GarbageCollected<DOMWindowLaunchQueue>, public Supplement<LocalDOMWindow> { - USING_GARBAGE_COLLECTED_MIXIN(DOMWindowLaunchParams); + USING_GARBAGE_COLLECTED_MIXIN(DOMWindowLaunchQueue); public: static const char kSupplementName[]; - explicit DOMWindowLaunchParams(); - ~DOMWindowLaunchParams(); + explicit DOMWindowLaunchQueue(); + ~DOMWindowLaunchQueue(); // IDL Interface. - static Member<LaunchParams> launchParams(LocalDOMWindow&); + static Member<LaunchQueue> launchQueue(LocalDOMWindow&); static void UpdateLaunchFiles(LocalDOMWindow*, HeapVector<Member<NativeFileSystemHandle>>); @@ -39,11 +40,11 @@ void Trace(blink::Visitor*) override; private: - static DOMWindowLaunchParams* FromState(LocalDOMWindow* window); + static DOMWindowLaunchQueue* FromState(LocalDOMWindow* window); - Member<LaunchParams> launch_params_; + Member<LaunchQueue> launch_queue_; }; } // namespace blink -#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_DOM_WINDOW_LAUNCH_PARAMS_H_ +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_DOM_WINDOW_LAUNCH_QUEUE_H_
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_params.idl b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl similarity index 79% rename from third_party/blink/renderer/modules/launch/dom_window_launch_params.idl rename to third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl index 1dd318ae..b0dd565 100644 --- a/third_party/blink/renderer/modules/launch/dom_window_launch_params.idl +++ b/third_party/blink/renderer/modules/launch/dom_window_launch_queue.idl
@@ -6,8 +6,8 @@ // Explainer: https://github.com/WICG/file-handling/blob/master/explainer.md [ - ImplementedAs=DOMWindowLaunchParams, + ImplementedAs=DOMWindowLaunchQueue, RuntimeEnabled=FileHandling ] partial interface Window { - readonly attribute LaunchParams launchParams; + readonly attribute LaunchQueue launchQueue; };
diff --git a/third_party/blink/renderer/modules/launch/launch_params.cc b/third_party/blink/renderer/modules/launch/launch_params.cc index 84fd390..280f67a 100644 --- a/third_party/blink/renderer/modules/launch/launch_params.cc +++ b/third_party/blink/renderer/modules/launch/launch_params.cc
@@ -12,20 +12,11 @@ namespace blink { -LaunchParams::LaunchParams() {} +LaunchParams::LaunchParams(HeapVector<Member<NativeFileSystemHandle>> files) + : files_(files) {} LaunchParams::~LaunchParams() = default; -void LaunchParams::SetFiles(HeapVector<Member<NativeFileSystemHandle>> files) { - files_ = std::move(files); -} - -void LaunchParams::SetFetchRequest( - mojom::blink::FetchAPIRequestPtr fetch_request) { - request_ = Member<Request>(); - fetch_request_ = std::move(fetch_request); -} - Request* LaunchParams::request(ScriptState* script_state) { if (!fetch_request_) return nullptr;
diff --git a/third_party/blink/renderer/modules/launch/launch_params.h b/third_party/blink/renderer/modules/launch/launch_params.h index 026f1423..7e958c1 100644 --- a/third_party/blink/renderer/modules/launch/launch_params.h +++ b/third_party/blink/renderer/modules/launch/launch_params.h
@@ -22,12 +22,9 @@ DEFINE_WRAPPERTYPEINFO(); public: - LaunchParams(); + LaunchParams(HeapVector<Member<NativeFileSystemHandle>> files); ~LaunchParams() override; - void SetFiles(HeapVector<Member<NativeFileSystemHandle>> files); - void SetFetchRequest(mojom::blink::FetchAPIRequestPtr fetch_request); - // LaunchParams IDL interface. const HeapVector<Member<NativeFileSystemHandle>>& files() { return files_; } Request* request(ScriptState* script_state);
diff --git a/third_party/blink/renderer/modules/launch/launch_queue.cc b/third_party/blink/renderer/modules/launch/launch_queue.cc new file mode 100644 index 0000000..9c2e9ca --- /dev/null +++ b/third_party/blink/renderer/modules/launch/launch_queue.cc
@@ -0,0 +1,47 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file + +#include "third_party/blink/renderer/modules/launch/launch_queue.h" + +#include "third_party/blink/renderer/bindings/modules/v8/v8_launch_consumer.h" +#include "third_party/blink/renderer/modules/launch/launch_params.h" +#include "third_party/blink/renderer/platform/heap/visitor.h" + +namespace blink { + +LaunchQueue::LaunchQueue() = default; + +LaunchQueue::~LaunchQueue() = default; + +void LaunchQueue::Enqueue(LaunchParams* params) { + if (!consumer_) { + unconsumed_launch_params_.push_back(params); + return; + } + + consumer_->Invoke(nullptr, params).Check(); +} + +void LaunchQueue::setConsumer(V8LaunchConsumer* consumer) { + consumer_ = consumer; + + // Consume all launch params now we have a consumer. + while (!unconsumed_launch_params_.IsEmpty()) { + // Get the first launch params and the queue and remove it before invoking + // the consumer, in case the consumer calls |setConsumer|. Each launchParams + // should be consumed by the most recently set consumer. + LaunchParams* params = unconsumed_launch_params_.at(0); + unconsumed_launch_params_.EraseAt(0); + + consumer_->Invoke(nullptr, params).Check(); + } +} + +void LaunchQueue::Trace(Visitor* visitor) { + visitor->Trace(unconsumed_launch_params_); + visitor->Trace(consumer_); + ScriptWrappable::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/modules/launch/launch_queue.h b/third_party/blink/renderer/modules/launch/launch_queue.h new file mode 100644 index 0000000..b4037793 --- /dev/null +++ b/third_party/blink/renderer/modules/launch/launch_queue.h
@@ -0,0 +1,40 @@ +// 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 + +#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_QUEUE_H_ +#define THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_QUEUE_H_ + +#include "third_party/blink/renderer/modules/launch/launch_params.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/heap/heap.h" +#include "third_party/blink/renderer/platform/heap/heap_allocator.h" + +namespace blink { + +class V8LaunchConsumer; +class Visitor; + +class LaunchQueue final : public ScriptWrappable { + DEFINE_WRAPPERTYPEINFO(); + + public: + LaunchQueue(); + ~LaunchQueue() override; + + void Enqueue(LaunchParams* params); + + // IDL implementation: + void setConsumer(V8LaunchConsumer*); + + // ScriptWrappable: + void Trace(blink::Visitor* visitor) override; + + private: + HeapVector<Member<LaunchParams>> unconsumed_launch_params_; + Member<V8LaunchConsumer> consumer_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_LAUNCH_LAUNCH_QUEUE_H_
diff --git a/third_party/blink/renderer/modules/launch/dom_window_launch_params.idl b/third_party/blink/renderer/modules/launch/launch_queue.idl similarity index 66% copy from third_party/blink/renderer/modules/launch/dom_window_launch_params.idl copy to third_party/blink/renderer/modules/launch/launch_queue.idl index 1dd318ae..46d0b9a 100644 --- a/third_party/blink/renderer/modules/launch/dom_window_launch_params.idl +++ b/third_party/blink/renderer/modules/launch/launch_queue.idl
@@ -5,9 +5,8 @@ // TODO(crbug.com/829689): Add link to spec once complete. // Explainer: https://github.com/WICG/file-handling/blob/master/explainer.md -[ - ImplementedAs=DOMWindowLaunchParams, - RuntimeEnabled=FileHandling -] partial interface Window { - readonly attribute LaunchParams launchParams; +[RuntimeEnabled=FileHandling] interface LaunchQueue { + void setConsumer(LaunchConsumer consumer); }; + +callback LaunchConsumer = any (LaunchParams params);
diff --git a/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc b/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc index e81a699..4cc9925 100644 --- a/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc +++ b/third_party/blink/renderer/modules/launch/web_launch_service_impl.cc
@@ -11,7 +11,7 @@ #include "third_party/blink/renderer/core/frame/local_dom_window.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/script/script.h" -#include "third_party/blink/renderer/modules/launch/dom_window_launch_params.h" +#include "third_party/blink/renderer/modules/launch/dom_window_launch_queue.h" #include "third_party/blink/renderer/platform/heap/heap.h" #include "third_party/blink/renderer/platform/heap/heap_allocator.h" @@ -43,7 +43,7 @@ std::move(entry), window_->GetExecutionContext())); } - DOMWindowLaunchParams::UpdateLaunchFiles(window_, std::move(files)); + DOMWindowLaunchQueue::UpdateLaunchFiles(window_, std::move(files)); } } // namespace blink
diff --git a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc index 41030d18..0a9a123 100644 --- a/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc +++ b/third_party/blink/renderer/modules/media_controls/media_controls_impl.cc
@@ -105,7 +105,7 @@ constexpr int kMinScrubbingMessageWidth = 300; -const char* kStateCSSClasses[8] = { +const char* const kStateCSSClasses[8] = { "state-no-source", // kNoSource "state-no-metadata", // kNotLoaded "state-loading-metadata-paused", // kLoadingMetadataPaused
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc index 85c5149b..3ffe246 100644 --- a/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc +++ b/third_party/blink/renderer/modules/mediacapturefromelement/canvas_capture_handler.cc
@@ -308,7 +308,7 @@ DCHECK(result); DCHECK(context_provider->GetGLHelper()); context_provider->GetGLHelper()->ReadbackTextureAsync( - texture_info.fID, image_size, + texture_info.fID, texture_info.fTarget, image_size, temp_argb_frame->visible_data(VideoFrame::kARGBPlane), kN32_SkColorType, WTF::Bind(&CanvasCaptureHandler::OnARGBPixelsReadAsync, weak_ptr_factory_.GetWeakPtr(), image, temp_argb_frame,
diff --git a/third_party/blink/renderer/modules/modules_idl_files.gni b/third_party/blink/renderer/modules/modules_idl_files.gni index c65f54c..3371822 100644 --- a/third_party/blink/renderer/modules/modules_idl_files.gni +++ b/third_party/blink/renderer/modules/modules_idl_files.gni
@@ -157,6 +157,7 @@ "filesystem/metadata.idl", "filesystem/metadata_callback.idl", "launch/launch_params.idl", + "launch/launch_queue.idl", "gamepad/gamepad.idl", "gamepad/gamepad_axis_event.idl", "gamepad/gamepad_button.idl", @@ -945,7 +946,7 @@ "filesystem/html_input_element_file_system.idl", "filesystem/shared_worker_global_scope_file_system.idl", "filesystem/window_file_system.idl", - "launch/dom_window_launch_params.idl", + "launch/dom_window_launch_queue.idl", "gamepad/navigator_gamepad.idl", "geolocation/navigator_geolocation.idl", "hid/navigator_hid.idl",
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.cc b/third_party/blink/renderer/modules/webaudio/audio_context.cc index 839d8c8..bd76a6a7 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_context.cc +++ b/third_party/blink/renderer/modules/webaudio/audio_context.cc
@@ -155,6 +155,20 @@ } Initialize(); + + // Compute the base latency now and cache the value since it doesn't change + // once the context is constructed. We need the destination to be initialized + // so we have to compute it here. + // + // TODO(hongchan): Due to the incompatible constructor between + // AudioDestinationNode and RealtimeAudioDestinationNode, casting directly + // from |destination()| is impossible. This is a temporary workaround until + // the refactoring is completed. + RealtimeAudioDestinationHandler& destination_handler = + static_cast<RealtimeAudioDestinationHandler&>( + destination()->GetAudioDestinationHandler()); + base_latency_ = destination_handler.GetFramesPerBuffer() / + static_cast<double>(sampleRate()); } void AudioContext::Uninitialize() { @@ -359,15 +373,7 @@ DCHECK(IsMainThread()); DCHECK(destination()); - // TODO(hongchan): Due to the incompatible constructor between - // AudioDestinationNode and RealtimeAudioDestinationNode, casting directly - // from |destination()| is impossible. This is a temporary workaround until - // the refactoring is completed. - RealtimeAudioDestinationHandler& destination_handler = - static_cast<RealtimeAudioDestinationHandler&>( - destination()->GetAudioDestinationHandler()); - return destination_handler.GetFramesPerBuffer() / - static_cast<double>(sampleRate()); + return base_latency_; } MediaElementAudioSourceNode* AudioContext::createMediaElementSource(
diff --git a/third_party/blink/renderer/modules/webaudio/audio_context.h b/third_party/blink/renderer/modules/webaudio/audio_context.h index e0d4cf1..013eee5 100644 --- a/third_party/blink/renderer/modules/webaudio/audio_context.h +++ b/third_party/blink/renderer/modules/webaudio/audio_context.h
@@ -176,6 +176,9 @@ // Represents whether a context is suspended by explicit |context.suspend()|. bool suspended_by_user_ = false; + // baseLatency for this context + double base_latency_ = 0; + // AudioContextManager for reporting audibility. mojo::Remote<mojom::blink::AudioContextManager> audio_context_manager_;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource.h b/third_party/blink/renderer/platform/graphics/canvas_resource.h index 2110069..b87748e0e 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource.h
@@ -160,6 +160,7 @@ Abandon(); } + void SetFilterQuality(SkFilterQuality filter) { filter_quality_ = filter; } // The filter quality to use when the resource is drawn by the compositor. SkFilterQuality FilterQuality() const { return filter_quality_; }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc index e1ee697..48e1f49 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -6,6 +6,7 @@ #include <utility> +#include "base/debug/stack_trace.h" #include "base/single_thread_task_runner.h" #include "components/viz/common/quads/compositor_frame.h" #include "components/viz/common/quads/texture_draw_quad.h" @@ -84,8 +85,6 @@ namespace { void UpdatePlaceholderImage( - base::WeakPtr<CanvasResourceDispatcher> dispatcher, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, int placeholder_canvas_id, scoped_refptr<blink::CanvasResource> canvas_resource, viz::ResourceId resource_id) { @@ -94,12 +93,24 @@ OffscreenCanvasPlaceholder::GetPlaceholderCanvasById( placeholder_canvas_id); if (placeholder_canvas) { - placeholder_canvas->SetOffscreenCanvasFrame( - std::move(canvas_resource), std::move(dispatcher), - std::move(task_runner), resource_id); + placeholder_canvas->SetOffscreenCanvasResource(std::move(canvas_resource), + resource_id); } } +void UpdatePlaceholderDispatcher( + base::WeakPtr<CanvasResourceDispatcher> dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> task_runner, + int placeholder_canvas_id) { + OffscreenCanvasPlaceholder* placeholder_canvas = + OffscreenCanvasPlaceholder::GetPlaceholderCanvasById( + placeholder_canvas_id); + // Note that the placeholder canvas may be destroyed when this post task get + // to executed. + if (placeholder_canvas) + placeholder_canvas->SetOffscreenCanvasDispatcher(dispatcher, task_runner); +} + } // namespace void CanvasResourceDispatcher::PostImageToPlaceholderIfNotBlocked( @@ -131,17 +142,13 @@ viz::ResourceId resource_id) { scoped_refptr<base::SingleThreadTaskRunner> dispatcher_task_runner = Thread::Current()->GetTaskRunner(); - // After this point, |canvas_resource| can only be used on the main thread, // until it is returned. canvas_resource->Transfer(); - PostCrossThreadTask( *Thread::MainThread()->Scheduler()->CompositorTaskRunner(), FROM_HERE, - CrossThreadBindOnce(UpdatePlaceholderImage, this->GetWeakPtr(), - WTF::Passed(std::move(dispatcher_task_runner)), - placeholder_canvas_id_, std::move(canvas_resource), - resource_id)); + CrossThreadBindOnce(UpdatePlaceholderImage, placeholder_canvas_id_, + std::move(canvas_resource), resource_id)); } void CanvasResourceDispatcher::DispatchFrameSync( @@ -405,6 +412,32 @@ sink_->DidDeleteSharedBitmap(std::move(id)); } +void CanvasResourceDispatcher::SetFilterQuality( + SkFilterQuality filter_quality) { + if (Client()) + Client()->SetFilterQualityInResource(filter_quality); +} + +void CanvasResourceDispatcher::SetPlaceholderCanvasDispatcher( + int placeholder_canvas_id) { + scoped_refptr<base::SingleThreadTaskRunner> dispatcher_task_runner = + Thread::Current()->GetTaskRunner(); + + // If the offscreencanvas is in the same tread as the canvas, we will update + // the canvas resource dispatcher directly. So Offscreen Canvas can behave in + // a more synchronous way when it's on the main thread. + if (IsMainThread()) { + UpdatePlaceholderDispatcher(this->GetWeakPtr(), dispatcher_task_runner, + placeholder_canvas_id); + } else { + PostCrossThreadTask( + *Thread::MainThread()->Scheduler()->CompositorTaskRunner(), FROM_HERE, + CrossThreadBindOnce(UpdatePlaceholderDispatcher, this->GetWeakPtr(), + WTF::Passed(std::move(dispatcher_task_runner)), + placeholder_canvas_id)); + } +} + void CanvasResourceDispatcher::ReclaimResourceInternal( viz::ResourceId resource_id) { auto it = resources_.find(resource_id);
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h index 30710a8..9a6ac41 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
@@ -23,6 +23,7 @@ class CanvasResourceDispatcherClient { public: virtual bool BeginFrame() = 0; + virtual void SetFilterQualityInResource(SkFilterQuality filter_quality) = 0; }; class PLATFORM_EXPORT CanvasResourceDispatcher @@ -81,6 +82,9 @@ ::gpu::mojom::blink::MailboxPtr id); void DidDeleteSharedBitmap(::gpu::mojom::blink::MailboxPtr id); + void SetFilterQuality(SkFilterQuality filter_quality); + void SetPlaceholderCanvasDispatcher(int placeholder_canvas_id); + private: friend class CanvasResourceDispatcherTest; struct FrameResource;
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc index 2f5d4eb..0a580ab 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider.cc
@@ -222,6 +222,7 @@ // readers. EndWriteAccess(); scoped_refptr<CanvasResource> resource = resource_; + resource->SetFilterQuality(FilterQuality()); if (ContextProviderWrapper() ->ContextProvider() ->GetCapabilities()
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc index 4a55245..7dce495a 100644 --- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc +++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -18,6 +18,7 @@ #include "third_party/blink/renderer/platform/graphics/test/gpu_memory_buffer_test_platform.h" #include "third_party/blink/renderer/platform/graphics/test/gpu_test_utils.h" #include "third_party/blink/renderer/platform/wtf/functional.h" +#include "third_party/skia/include/core/SkFilterQuality.h" using testing::_; using testing::InSequence; @@ -34,6 +35,7 @@ MockCanvasResourceDispatcherClient() = default; MOCK_METHOD0(BeginFrame, bool()); + MOCK_METHOD1(SetFilterQualityInResource, void(SkFilterQuality)); }; } // anonymous namespace
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc index 84dbe25..87831e86 100644 --- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc +++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.cc
@@ -17,7 +17,6 @@ typedef HashMap<int, blink::OffscreenCanvasPlaceholder*> PlaceholderIdMap; PlaceholderIdMap& placeholderRegistry() { - DCHECK(IsMainThread()); DEFINE_STATIC_LOCAL(PlaceholderIdMap, s_placeholderRegistry, ()); return s_placeholderRegistry; } @@ -40,6 +39,14 @@ } } +void UpdateDispatcherFilterQuality( + base::WeakPtr<blink::CanvasResourceDispatcher> dispatcher, + SkFilterQuality filter) { + if (dispatcher) { + dispatcher->SetFilterQuality(filter); + } +} + } // unnamed namespace namespace blink { @@ -48,17 +55,13 @@ UnregisterPlaceholderCanvas(); } -void OffscreenCanvasPlaceholder::SetOffscreenCanvasFrame( +void OffscreenCanvasPlaceholder::SetOffscreenCanvasResource( scoped_refptr<CanvasResource> new_frame, - base::WeakPtr<CanvasResourceDispatcher> dispatcher, - scoped_refptr<base::SingleThreadTaskRunner> task_runner, viz::ResourceId resource_id) { DCHECK(IsOffscreenCanvasRegistered()); DCHECK(new_frame); ReleaseOffscreenCanvasFrame(); placeholder_frame_ = std::move(new_frame); - frame_dispatcher_ = std::move(dispatcher); - frame_dispatcher_task_runner_ = std::move(task_runner); placeholder_frame_resource_id_ = resource_id; if (animation_state_ == kShouldSuspendAnimation) { @@ -72,16 +75,56 @@ } } +void OffscreenCanvasPlaceholder::SetOffscreenCanvasDispatcher( + base::WeakPtr<CanvasResourceDispatcher> dispatcher, + scoped_refptr<base::SingleThreadTaskRunner> task_runner) { + DCHECK(IsOffscreenCanvasRegistered()); + frame_dispatcher_ = std::move(dispatcher); + frame_dispatcher_task_runner_ = std::move(task_runner); + // The UpdateOffscreenCanvasFilterQuality could be called to change the filter + // quality before this function. We need to first apply the filter changes to + // the corresponding offscreen canvas. + if (filter_quality_) { + SkFilterQuality quality = filter_quality_.value(); + filter_quality_ = base::nullopt; + UpdateOffscreenCanvasFilterQuality(quality); + } +} + void OffscreenCanvasPlaceholder::ReleaseOffscreenCanvasFrame() { DCHECK(IsOffscreenCanvasRegistered()); - if (placeholder_frame_) { - DCHECK(frame_dispatcher_task_runner_); - placeholder_frame_->Transfer(); + if (!placeholder_frame_) + return; + + DCHECK(frame_dispatcher_task_runner_); + placeholder_frame_->Transfer(); + PostCrossThreadTask( + *frame_dispatcher_task_runner_, FROM_HERE, + CrossThreadBindOnce(releaseFrameToDispatcher, frame_dispatcher_, + std::move(placeholder_frame_), + placeholder_frame_resource_id_)); +} + +void OffscreenCanvasPlaceholder::UpdateOffscreenCanvasFilterQuality( + SkFilterQuality filter_quality) { + DCHECK(IsOffscreenCanvasRegistered()); + if (!frame_dispatcher_task_runner_) { + filter_quality_ = filter_quality; + return; + } + + if (filter_quality_ == filter_quality) + return; + + filter_quality_ = filter_quality; + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + Thread::Current()->GetTaskRunner(); + if (task_runner == frame_dispatcher_task_runner_) { + UpdateDispatcherFilterQuality(frame_dispatcher_, filter_quality); + } else { PostCrossThreadTask(*frame_dispatcher_task_runner_, FROM_HERE, - CrossThreadBindOnce(releaseFrameToDispatcher, - std::move(frame_dispatcher_), - std::move(placeholder_frame_), - placeholder_frame_resource_id_)); + CrossThreadBindOnce(UpdateDispatcherFilterQuality, + frame_dispatcher_, filter_quality)); } }
diff --git a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h index dc91d6cb..c21fdd43 100644 --- a/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h +++ b/third_party/blink/renderer/platform/graphics/offscreen_canvas_placeholder.h
@@ -12,6 +12,7 @@ #include "components/viz/common/resources/resource_id.h" #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/skia/include/core/SkFilterQuality.h" namespace blink { @@ -24,11 +25,12 @@ public: ~OffscreenCanvasPlaceholder(); - virtual void SetOffscreenCanvasFrame( - scoped_refptr<CanvasResource>, + virtual void SetOffscreenCanvasResource(scoped_refptr<CanvasResource>, + viz::ResourceId resource_id); + void SetOffscreenCanvasDispatcher( base::WeakPtr<CanvasResourceDispatcher>, - scoped_refptr<base::SingleThreadTaskRunner>, - viz::ResourceId resource_id); + scoped_refptr<base::SingleThreadTaskRunner>); + void ReleaseOffscreenCanvasFrame(); void SetSuspendOffscreenCanvasAnimation(bool); @@ -46,6 +48,8 @@ return placeholder_id_ != kNoPlaceholderId; } + void UpdateOffscreenCanvasFilterQuality(SkFilterQuality filter_quality); + private: bool PostSetSuspendAnimationToOffscreenCanvasThread(bool suspend); @@ -67,6 +71,7 @@ kShouldActivateAnimation, }; AnimationState animation_state_ = kActiveAnimation; + base::Optional<SkFilterQuality> filter_quality_ = base::nullopt; }; } // namespace blink
diff --git a/third_party/blink/renderer/platform/json/json_values.cc b/third_party/blink/renderer/platform/json/json_values.cc index 21e84cc..1d35618 100644 --- a/third_party/blink/renderer/platform/json/json_values.cc +++ b/third_party/blink/renderer/platform/json/json_values.cc
@@ -87,9 +87,9 @@ } // anonymous namespace -const char* kJSONNullString = "null"; -const char* kJSONTrueString = "true"; -const char* kJSONFalseString = "false"; +const char kJSONNullString[] = "null"; +const char kJSONTrueString[] = "true"; +const char kJSONFalseString[] = "false"; void EscapeStringForJSON(const String& str, StringBuilder* dst) { for (unsigned i = 0; i < str.length(); ++i) {
diff --git a/third_party/blink/renderer/platform/json/json_values.h b/third_party/blink/renderer/platform/json/json_values.h index a3808a1eb..cd93b39 100644 --- a/third_party/blink/renderer/platform/json/json_values.h +++ b/third_party/blink/renderer/platform/json/json_values.h
@@ -265,9 +265,9 @@ Vector<std::unique_ptr<JSONValue>> data_; }; -extern const char* kJSONNullString; -extern const char* kJSONTrueString; -extern const char* kJSONFalseString; +extern const char kJSONNullString[]; +extern const char kJSONTrueString[]; +extern const char kJSONFalseString[]; PLATFORM_EXPORT void EscapeStringForJSON(const String&, StringBuilder*); void DoubleQuoteStringForJSON(const String&, StringBuilder*);
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/nested-overflow-subtree-layout-ref.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/nested-overflow-subtree-layout-ref.html new file mode 100644 index 0000000..77b0de7f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/nested-overflow-subtree-layout-ref.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<head> + <link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org"> + <link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring/"> + <script src="/common/reftest-wait.js"></script> +</head> +<style> +#outer { + overflow: hidden; + width: 500px; + height: 500px; +} +#inner { + overflow: auto; + position: relative; + width: 500px; + height: 2000px; +} +p { + + font: 48pt monospace; +} +</style> +</head> +<body> +<div id="outer"> + <div id="inner"> + <p>Anchor</p> + </div> +</div> +<script> +const outer = document.querySelector("#outer"); +const inner = document.querySelector("#inner"); + +onload = () => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + outer.scrollTo(0, 70); + document.documentElement.removeAttribute("class"); + }); + }); +}; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/nested-overflow-subtree-layout.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/nested-overflow-subtree-layout.html new file mode 100644 index 0000000..ffa52b6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-anchoring/nested-overflow-subtree-layout.html
@@ -0,0 +1,50 @@ +<!DOCTYPE html> +<head> + <title>Test that subtree layout with nested overflow preserves scroll anchoring.</title> + <link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org"> + <link rel="help" href="https://drafts.csswg.org/css-scroll-anchoring/"> + <link rel="match" href="nested-overflow-subtree-layout-ref.html"> + <script src="/common/reftest-wait.js"></script> +</head> +<style> +#outer { + overflow: hidden; + width: 500px; + height: 500px; +} +#inner { + overflow: auto; + position: relative; + width: 500px; + height: 2000px; +} +p { + + font: 48pt monospace; +} +</style> +</head> +<body> +<div id="outer"> + <div id="inner"> + <p>Anchor</p> + </div> +</div> +<script> +const outer = document.querySelector("#outer"); +const inner = document.querySelector("#inner"); + +onload = () => { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + outer.scrollTo(0, 70); + requestAnimationFrame(() => { + const elem = document.createElement("p"); + elem.textContent = "FAIL"; + inner.insertBefore(elem, inner.firstChild); + document.documentElement.removeAttribute("class"); + }); + }); + }); +}; +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-017.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-017.html new file mode 100644 index 0000000..a2521cb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-017.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.3. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="The text is wrapped into two lines, since there is no need to break the second line using the space in the middle."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXX<br>X X</div> + <div class="test">XXXX<span> </span>X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-001.html new file mode 100644 index 0000000..a4158dc --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-001.html
@@ -0,0 +1,39 @@ + +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' can't prevent overflow under 'white-space: pre', because it line wrapping is not allowed. "> +<style> +div { + position: relative; + font: 10px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + line-break: anywhere; + + white-space: pre; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX<span style="color: green">XXXX</span>XX</div> + <div class="test">XXXX XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-002.html new file mode 100644 index 0000000..2fbb53d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-002.html
@@ -0,0 +1,40 @@ + +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-nowrap"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' can't prevent overflow under 'white-space: nowrap', because it line wrapping is not allowed. "> +<style> +div { + position: relative; + font: 10px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 5ch; + line-break: anywhere; + + white-space: nowrap; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX XX</div> + <div class="test">XXXX XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-003.html new file mode 100644 index 0000000..3002dc10 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-003.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' can't prevent overflow under 'white-space: pre', because it line wrapping is not allowed. "> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; + + white-space: pre; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"><span style="color: green">X</span>XXX</div> + <div class="test"> XXX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-004.html new file mode 100644 index 0000000..e6e1b39 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-004.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-normal"> +<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="The line is wrapped ignoring the white space, which will be removed honoring 'white-space: normal'"> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + line-break: anywhere; + + white-space: normal; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXX<br>XX</div> + <div class="test">XXX<span style="background: red"> </span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-005.html new file mode 100644 index 0000000..2f64d870 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-005.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-normal"> +<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="The line is wrapped ignoring the white space, which will be removed honoring 'white-space: normal'"> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + line-break: anywhere; + + white-space: normal; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX<br>X</div> + <div class="test"><span style="background: red"> </span>XXXXX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-006.html new file mode 100644 index 0000000..c804e37 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-006.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' can't break a preserved sequence of spaces under 'white-spate: pre-wrap', which should hang instead."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 2ch; + + line-break: anywhere; + white-space: pre-wrap; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX<br>XX</div> + <div class="test">X<span style="background: green"> </span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-007.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-007.html new file mode 100644 index 0000000..d9b266d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-007.html
@@ -0,0 +1,40 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-pre-wrap"> +<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' can't break before the first white-space affter a word under 'white-spate: pre-wrap', which should hang instead."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + + line-break: anywhere; + white-space: pre-wrap; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX<br>XX</div> + <div class="test">XXX<span style="background: green"> </span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-008.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-008.html new file mode 100644 index 0000000..aebd31ea --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-008.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-break-spaces"> +<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' allows preserved white spaces at the end of the line, honoring 'white-space: break-spaces'."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + + line-break: anywhere; + white-space: break-spaces; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX<span style="color: green">XX<br>XX</span>XX<br>XXX</div> + <div class="test">XX XXXXX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-009.html new file mode 100644 index 0000000..f536c90 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-and-white-space-009.html
@@ -0,0 +1,39 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere and the white-space property</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="3. White Space and Wrapping: the white-space property" href="https://drafts.csswg.org/css-text-3/#white-space-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-white-space-break-spaces"> +<link rel="help" title="4.1.3. Phase II: Trimming and Positioning" href="https://drafts.csswg.org/css-text-3/#white-space-phase-2"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'line-break: anywhere' allows breaking before the first character of a preserved white space sequence, honoring 'white-space: break-spaces'."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + + line-break: anywhere; + white-space: break-spaces; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX<br><span style="color: green">XXX</span>X<br>XXXX<br><span style="color: green">X</span>X</div> + <div class="test">XXXX XXXXX X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-001.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-001.html new file mode 100644 index 0000000..d18df4b3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-001.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the WJ classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + width: 100px; + height: 100px; + background: red; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX⁠XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-002.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-002.html new file mode 100644 index 0000000..1255aa1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-002.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the WJ classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + width: 100px; + height: 100px; + background: red; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XXXX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-003.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-003.html new file mode 100644 index 0000000..7fe230e890 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-003.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the ZW classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + width: 100px; + height: 100px; + color: red; + background: green; + z-index: -1; +} +.test { + color: green; + width: 4ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXX<br>XX</div> + <div class="test">..​...X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-004.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-004.html new file mode 100644 index 0000000..13706d5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-004.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + width: 100px; + height: 100px; + background: red; + z-index: -1; +} +.test { + color: green; + width: 3ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-005.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-005.html new file mode 100644 index 0000000..175228d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-005.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX<br><span style="color: green">X</span>X</div> + <div class="test">XX X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-006.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-006.html new file mode 100644 index 0000000..9bb557e7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-006.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-007.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-007.html new file mode 100644 index 0000000..7f90bfd --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-007.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 20px / 1 Ahem; +} +.red { + position: absolute; + background: green; + height: 100px; + color: red; + z-index: -1; +} +.test { + color: green; + width: 5ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXXXX<br>XX</div> + <div class="test">XXX<span style="background: green"> X</span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-008.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-008.html new file mode 100644 index 0000000..40826540 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-008.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + z-index: -1; +} +.test { + color: green; + width: 3ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX<br>X</div> + <div class="test">XX X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-009.html new file mode 100644 index 0000000..6d6ca3f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-009.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX<br>X</div> + <div class="test">XX᠎X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-010.html new file mode 100644 index 0000000..5f152c6 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-010.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX ᠎XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-011.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-011.html new file mode 100644 index 0000000..2196d98 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-011.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX<br>X</div> + <div class="test">XX͏X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-012.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-012.html new file mode 100644 index 0000000..110d9ca --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-012.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX ͏XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-013.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-013.html new file mode 100644 index 0000000..2cda76c5c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-013.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX‑X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-014.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-014.html new file mode 100644 index 0000000..d79efb7 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-014.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the GL classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX X<br>XX</div> + <div class="test">XX ‑XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-015.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-015.html new file mode 100644 index 0000000..5eecd03 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-015.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the ZWJ classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 50px / 1 Ahem; +} +.red { + position: absolute; + background: red; + height: 100px; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 2ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"></div> + <div class="test">XX‍XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-016.html b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-016.html new file mode 100644 index 0000000..d4ab337 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/line-break/line-break-anywhere-overrides-uax-behavior-016.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: line-break: anywhere overrides behavior defined for the WJ, ZW, GL, and ZWJ classes</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.1. Line Breaking Details" href="https://drafts.csswg.org/css-text-3/#line-break-details"> +<link rel="help" title="5.3. Line Breaking Strictness: the line-break property" href="https://drafts.csswg.org/css-text-3/#line-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-line-break-anywhere"> +<link rel="match" href="reference/line-break-anywhere-004-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="Except where explicitly defined by 'line-break: anywhere' line breaking behavior defined for the ZWJ classes in [UAX14] must be honored. "> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 4ch; + line-break: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XX X<br>X</div> + <div class="test">XX ‍XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-009.html new file mode 100644 index 0000000..90f2ad33 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-009.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: overflow-wrap: anywhere</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.5. Overflow Wrapping: the overflow-wrap/word-wrap property" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-overflow-wrap-anywhere"> +<link rel="match" href="reference/overflow-wrap-break-word-001-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="The text is wrapped into two lines, since there is no need to break the second line using the space in the middle."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.ref { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + + overflow-wrap: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="ref">XXX<br>X X</div> + <div class="test">XXXX<span> </span>X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-010.html new file mode 100644 index 0000000..0b4b75b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-anywhere-010.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: overflow-wrap: anywhere</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.5. Overflow Wrapping: the overflow-wrap/word-wrap property" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-overflow-wrap-anywhere"> +<link rel="match" href="reference/overflow-wrap-break-word-001-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'overflow-wrap: anywhere' applies correctly when there is styled text using 'span' elements."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: transparent; + width: 4ch; + overflow-wrap: anywhere; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red"><span style="color: green">XX</span>XX<br>XX</div> + <div class="test">XX<span style="color: green">XXXX</span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-009.html b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-009.html new file mode 100644 index 0000000..fbbcf22 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-009.html
@@ -0,0 +1,36 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: overflow-wrap: break-word</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.5. Overflow Wrapping: the overflow-wrap/word-wrap property" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-overflow-wrap-break-word"> +<link rel="match" href="reference/overflow-wrap-break-word-001-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="The text is wrapped into two lines, since there is no need to break the second line using the space in the middle."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.ref { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + + overflow-wrap: break-word; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="ref">XXX<br>X X</div> + <div class="test">XXXX<span> </span>X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-010.html new file mode 100644 index 0000000..da45dea2 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/overflow-wrap/overflow-wrap-break-word-010.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: overflow-wrap: break-word</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.5. Overflow Wrapping: the overflow-wrap/word-wrap property" href="https://drafts.csswg.org/css-text-3/#overflow-wrap-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-overflow-wrap-break-word"> +<link rel="match" href="reference/overflow-wrap-break-word-001-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="'overflow-wrap: break-word' applies correctly when there is styled text using 'span' elements."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.ref { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: transparent; + width: 4ch; + overflow-wrap: break-word; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="ref"><span style="color: green">XX</span>XX<br>XX</div> + <div class="test">XX<span style="color: green">XXXX</span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-029.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-029.html new file mode 100644 index 0000000..3e0a1e14 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-029.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: word-break: break-all</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-break-all"> +<link rel="match" href="reference/word-break-break-all-010-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="The text is wrapped into two lines, since there is no need to break the second line using the space in the middle."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.red { + position: absolute; + background: green; + color: red; + width: 100px; + height: 100px; + z-index: -1; +} +.test { + color: green; + width: 3ch; + word-break: break-all; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="red">XXX<br>X X</div> + <div class="test">XXXX<span> </span>X</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-030.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-030.html new file mode 100644 index 0000000..e6a8a00 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-030.html
@@ -0,0 +1,34 @@ +<!DOCTYPE html> +<html lang=en> +<meta charset="utf-8"> +<title>CSS Text Test: word-break: break-all</title> +<link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> +<link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property"> +<link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-break-all"> +<link rel="match" href="reference/word-break-break-all-010-ref.html"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> +<meta name="flags" content="Ahem"> +<meta name="assert" content="word-break: break-all applies correctly when there is styled text using 'span' elemetns."> +<style> +div { + position: relative; + font: 25px / 1 Ahem; +} +.ref { + position: absolute; + background: green; + color: red; + height: 100px; + z-index: -1; +} +.test { + color: transparent; + width: 4ch; + word-break: break-all; +} +</style> +<body> + <p>Test passes if there is a <strong>filled green square</strong> and <strong>no red</strong>.</p> + <div class="ref"><span style="color: green">XX</span>XX<br>XX</div> + <div class="test">XX<span style="color: green">XXXX</span>XX</div> +</body>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-inline-010.html b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-inline-010.html index 875a3623..3c2df3c 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-inline-010.html +++ b/third_party/blink/web_tests/external/wpt/css/css-text/word-break/word-break-break-all-inline-010.html
@@ -5,9 +5,10 @@ <link rel="author" title="Javier Fernandez Garcia-Boente" href="mailto:jfernandez@igalia.com"> <link rel="help" title="5.2. Breaking Rules for Letters: the word-break property" href="https://drafts.csswg.org/css-text-3/#word-break-property"> <link rel="help" href="https://drafts.csswg.org/css-text-3/#valdef-word-break-break-all"> +<link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> <meta name="flags" content="Ahem"> <link rel="match" href="reference/word-break-break-all-010-ref.html"> -<meta name="assert" content="'overflow-wrap: anywhere' allows to break after the first character of the inline-block it applies to"> +<meta name="assert" content="'word-break: break-all' allows to break after the first character of the inline-block it applies to"> <link rel="stylesheet" type="text/css" href="/fonts/ahem.css" /> <style> div, span {
diff --git a/third_party/blink/web_tests/fast/harness/results.html b/third_party/blink/web_tests/fast/harness/results.html index 2682638..8d9a9bd 100644 --- a/third_party/blink/web_tests/fast/harness/results.html +++ b/third_party/blink/web_tests/fast/harness/results.html
@@ -528,8 +528,7 @@ let pathParser = new PathParser(path); let html = ` <div class='expect' tabindex='0' data-id='${test.expectId}'> - <div class='details'></div>${Report.printFlag(test)} - ${pathParser.dir}<a target='test' tabindex='-1' href='${pathParser.testHref}'>${pathParser.file}${pathParser.query}</a> + <div class='details'></div>${Report.printFlag(test)}${pathParser.dir}<a target='test' tabindex='-1' href='${pathParser.testHref}'>${pathParser.file}${pathParser.query}</a> </div>`; traversal.html.push(html); },
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/fetch/fetch-cookies-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch/fetch-cookies-expected.txt new file mode 100644 index 0000000..91af266 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch/fetch-cookies-expected.txt
@@ -0,0 +1,25 @@ +Tests that fetch exposes cookies for CORS XHRs. +Request to https://site1.a.test/, type: Document +Request to https://site2.a.test/, type: Document +Request to https://site1.a.test/post, type: XHR +Cookies after cross-origin XHR: +undefined +Request to https://site2.a.test/post, type: XHR +Cookies after same-origin XHR: +CrossOriginCookie=om-nom-nom-nom; SameOriginCookie=me-want-cookie +Request to https://site1.a.test/post, type: XHR +Cookies after cross-origin fetch with {credentials: 'include'}: +CrossOriginCookie=om-nom-nom-nom +Request to https://site1.a.test/post, type: XHR +Cookies after cross-origin fetch with {credentials: 'same-origin'}: +undefined +Request to https://site2.a.test/post, type: XHR +Cookies after same-origin fetch with {credentials: 'same-origin'}: +CrossOriginCookie=om-nom-nom-nom; SameOriginCookie=me-want-cookie +Request to https://site2.a.test/post, type: XHR +Cookies after same-origin fetch with {credentials: 'include', mode: 'no-cors'}: +CrossOriginCookie=om-nom-nom-nom; SameOriginCookie=me-want-cookie +Request to https://site1.a.test/post, type: XHR +Cookies after cross-origin fetch with {credentials: 'include', mode: 'no-cors'}: +CrossOriginCookie=om-nom-nom-nom +
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/fetch/fetch-cookies.js b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch/fetch-cookies.js new file mode 100644 index 0000000..8e6971d1 --- /dev/null +++ b/third_party/blink/web_tests/http/tests/inspector-protocol/fetch/fetch-cookies.js
@@ -0,0 +1,75 @@ +(async function(testRunner) { + const {page, session, dp} = await testRunner.startBlank( + `Tests that fetch exposes cookies for CORS XHRs.`); + + const FetchHelper = await testRunner.loadScript('resources/fetch-test.js'); + const helper = new FetchHelper(testRunner, testRunner.browserP()); + await helper.enable(); + + helper.onceRequest(/site1.a.test/).fulfill({ + responseCode: 302, + responseHeaders: [ + {name: 'Location', value: 'https://site2.a.test'}, + {name: 'Set-Cookie', value: 'CrossOriginCookie=om-nom-nom-nom; path=/; domain=.a.test; Secure; HttpOnly; SameSite=none'}, + ] + }); + + helper.onceRequest(/site2.a.test/).fulfill({ + responseCode: 200, + responseHeaders: [ + {name: 'Set-Cookie', value: 'SameOriginCookie=me-want-cookie; Secure; domain=site2.a.test; HttpOnly; SameSite=none'}, + ], + body: btoa("<html></html>") + }); + + await dp.Page.enable(); + await session.navigate('https://site1.a.test'); + + async function makeRequestAndDumpCookies(code, description) { + session.evaluate(code); + const request = await helper.onceRequest(/a.test/).matched(); + testRunner.log(`Cookies after ${description}:`); + testRunner.log(request.request.headers['Cookie']); + dp.Fetch.fulfillRequest({requestId: request.requestId, responseCode: 200}); + } + + await makeRequestAndDumpCookies(` + const xhr = new XMLHttpRequest(); + xhr.open('POST', 'https://site1.a.test/post'); + xhr.send('postdata'); + `, 'cross-origin XHR'); + + await makeRequestAndDumpCookies(` + const xhr2 = new XMLHttpRequest(); + xhr2.open('POST', '/post'); + xhr2.send('postdata'); + `, 'same-origin XHR'); + + await makeRequestAndDumpCookies(` + fetch('https://site1.a.test/post', + {method: 'POST', body: 'postdata', credentials: 'include'}); + `, `cross-origin fetch with {credentials: 'include'}`); + + await makeRequestAndDumpCookies(` + fetch('https://site1.a.test/post', + {method: 'POST', body: 'postdata', credentials: 'same-origin'}); + `, `cross-origin fetch with {credentials: 'same-origin'}`); + + await makeRequestAndDumpCookies(` + fetch('/post', + {method: 'POST', body: 'postdata', credentials: 'same-origin'}); + `, `same-origin fetch with {credentials: 'same-origin'}`); + + await makeRequestAndDumpCookies(` + fetch('/post', + {method: 'POST', body: 'postdata', credentials: 'include', mode: 'no-cors'}); + `, `same-origin fetch with {credentials: 'include', mode: 'no-cors'}`); + + await makeRequestAndDumpCookies(` + fetch('https://site1.a.test/post', + {method: 'POST', body: 'postdata', credentials: 'include', mode: 'no-cors'}); + `, `cross-origin fetch with {credentials: 'include', mode: 'no-cors'}`); + + testRunner.completeTest(); +}) +
diff --git a/third_party/blink/web_tests/inspector-protocol/timeline/timeline-layout.js b/third_party/blink/web_tests/inspector-protocol/timeline/timeline-layout.js index d9dc48c..9507a16 100644 --- a/third_party/blink/web_tests/inspector-protocol/timeline/timeline-layout.js +++ b/third_party/blink/web_tests/inspector-protocol/timeline/timeline-layout.js
@@ -21,23 +21,21 @@ await tracingHelper.invokeAsyncWithTracing(performActions); var schedRecalc = tracingHelper.findEvent('ScheduleStyleRecalculation', 'I'); - var recalcBegin = tracingHelper.findEvent('UpdateLayoutTree', 'B'); - var recalcEnd = tracingHelper.findEvent('UpdateLayoutTree', 'E'); - testRunner.log('UpdateLayoutTree frames match: ' + (schedRecalc.args.data.frame === recalcBegin.args.beginData.frame)); - testRunner.log('UpdateLayoutTree elementCount > 0: ' + (recalcEnd.args.elementCount > 0)); + var recalc = tracingHelper.findEvent('UpdateLayoutTree', 'X'); + testRunner.log('UpdateLayoutTree frames match: ' + (schedRecalc.args.data.frame === recalc.args.beginData.frame)); + testRunner.log('UpdateLayoutTree elementCount > 0: ' + (recalc.args.elementCount > 0)); var invalidate = tracingHelper.findEvent('InvalidateLayout', 'I'); - var layoutBegin = tracingHelper.findEvent('Layout', 'B'); - var layoutEnd = tracingHelper.findEvent('Layout', 'E'); + var layout = tracingHelper.findEvent('Layout', 'X'); - testRunner.log('InvalidateLayout frames match: ' + (recalcBegin.args.beginData.frame === invalidate.args.data.frame)); + testRunner.log('InvalidateLayout frames match: ' + (recalc.args.beginData.frame === invalidate.args.data.frame)); - var beginData = layoutBegin.args.beginData; + var beginData = layout.args.beginData; testRunner.log('Layout frames match: ' + (invalidate.args.data.frame === beginData.frame)); testRunner.log('dirtyObjects > 0: ' + (beginData.dirtyObjects > 0)); testRunner.log('totalObjects > 0: ' + (beginData.totalObjects > 0)); - var endData = layoutEnd.args.endData; + var endData = layout.args.endData; testRunner.log('has rootNode id: ' + (endData.rootNode > 0)); testRunner.log('has root quad: ' + !!endData.root);
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png index 62554e4..810bfa7f 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..b1f1372a --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png index 068fcacd..92616c5 100644 --- a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png +++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..3d591ddf --- /dev/null +++ b/third_party/blink/web_tests/platform/linux/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png new file mode 100644 index 0000000..67ca40b --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..cec2c10 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.10/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png new file mode 100644 index 0000000..67ca40b --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..cec2c10 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.11/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png new file mode 100644 index 0000000..67ca40b --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..cec2c10 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-mac10.12/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png new file mode 100644 index 0000000..67ca40b --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..cec2c10 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac-retina/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png index 891200f..67ca40b 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..cec2c10 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png index a61614d..ac67df2 100644 --- a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png +++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..60d93a46 --- /dev/null +++ b/third_party/blink/web_tests/platform/mac/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png new file mode 100644 index 0000000..26dd754 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..c13cbb4 --- /dev/null +++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png index 8e796d7e..e1b37cb 100644 --- a/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png +++ b/third_party/blink/web_tests/platform/win/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png new file mode 100644 index 0000000..26dd754 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..c13cbb4 --- /dev/null +++ b/third_party/blink/web_tests/platform/win7/virtual/controls-refresh-hc/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic.html b/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic.html index 45700a5..28c32c7 100644 --- a/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic.html +++ b/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-multiple-appearance-basic.html
@@ -73,6 +73,20 @@ </optgroup> </select> +<select multiple style="background-color: blue;"> + <optgroup label="background-color: blue"> + <option selected>first selected option</option> + <option>unselected option</option> + <option selected>second selected option</option> + </optgroup> +</select> + +<select multiple style="background-color: blue;"> + <option selected>selected option</option> + <option>unselected option</option> + <option>unselected option</option> +</select> <br> + <!-- shadow --> <select multiple style="box-shadow: 4px 4px 10px rgba(255,0,0,0.5), inset 4px 4px 4px rgba(0,255,0,0.5);"> <optgroup label="box-shadow">
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png b/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png new file mode 100644 index 0000000..433dc87 --- /dev/null +++ b/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic.html b/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic.html new file mode 100644 index 0000000..9e72a60 --- /dev/null +++ b/third_party/blink/web_tests/virtual/controls-refresh/color-scheme/select/select-popup-appearance-basic.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<script> +testRunner.waitUntilDone(); +</script> +<script src="../../../../fast/forms/resources/picker-common.js"></script> +<select id="menu" style="background-color: blue;"> + <optgroup label="Theropods"> + <option>Tyrannosaurus</option> + <option>Velociraptor</option> + <option>Deinonychus</option> + </optgroup> + <optgroup label="Sauropods"> + <option>Diplodocus</option> + <option>Saltasaurus</option> + <option>Apatosaurus</option> + </optgroup> +</select> +<script> +openPicker(document.getElementById('menu'), () => testRunner.notifyDone(), () => testRunner.notifyDone()); +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchParams-exist.tentative.window-expected.txt b/third_party/blink/web_tests/virtual/file-handling/file-handling/launchParams-exist.tentative.window-expected.txt deleted file mode 100644 index 265b596..0000000 --- a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchParams-exist.tentative.window-expected.txt +++ /dev/null
@@ -1,6 +0,0 @@ -This is a testharness.js-based test. -PASS launchParams should be available off the global object. -PASS files should default to an empty array. -FAIL request is available and correct. assert_true: request must be a Request. expected true got false -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchParams-exist.tentative.window.html b/third_party/blink/web_tests/virtual/file-handling/file-handling/launchParams-exist.tentative.window.html deleted file mode 100644 index 03a5eda8..0000000 --- a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchParams-exist.tentative.window.html +++ /dev/null
@@ -1,28 +0,0 @@ -<!doctype html> -<title>Launch Params are available from JavaScript.</title> -<link rel="help" href="https://github.com/WICG/file-handling/blob/master/explainer.md"> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -<script> - -test(() => { - assert_true('launchParams' in window, 'window must have launchParams.'); - assert_true(window.launchParams instanceof LaunchParams, 'launchParams must be a LaunchParams.'); -}, 'launchParams should be available off the global object.'); - -test(() => { - assert_true('files' in window.launchParams, 'launchParams has files.'); - assert_true(Array.isArray(window.launchParams.files), 'files must be an array.'); - - assert_equals(window.launchParams.files.length, 0); -}, 'files should default to an empty array.'); - -test(() => { - assert_true('request' in window.launchParams, 'launchParams has request.'); - assert_true(window.launchParams.request instanceof Request, 'request must be a Request.'); - - assert_true('url' in window.launchParams.request, 'request has a url.'); - assert_equals(window.launchParams.request.url, window.location.href); -}, 'request is available and correct.'); - -</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html b/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html new file mode 100644 index 0000000..2542dc39 --- /dev/null +++ b/third_party/blink/web_tests/virtual/file-handling/file-handling/launchQueue-exists.tentative.window.html
@@ -0,0 +1,24 @@ +<!doctype html> +<title>Launch Params are available from JavaScript.</title> +<link rel="help" href="https://github.com/WICG/file-handling/blob/master/explainer.md"> +<script src="../../../resources/testharness.js"></script> +<script src="../../../resources/testharnessreport.js"></script> +<script> + +test(() => { + assert_true('launchQueue' in window, 'window must have a launchQueue.'); + assert_true(window.launchQueue instanceof LaunchQueue, 'launchQueue must be a LaunchQueue.'); +}, 'launchQueue should be available off the global object.'); + +test(() => { + assert_true('setConsumer' in window.launchQueue, 'clients should be able to set a consumer for launches.'); + assert_equals(typeof window.launchQueue.setConsumer, 'function', 'launchQueue.setConsumer should be a function.'); + + // There should be no events in the launchQueue in the test. + window.launchQueue.setConsumer(launchParams => { + console.error(launchParams); + throw new Error("This should not be reached in the test"); + }); +}, 'setConsumer should be a function.'); + +</script> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAuto-expected.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAuto-expected.html new file mode 100644 index 0000000..644a610 --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAuto-expected.html
@@ -0,0 +1,22 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + #can { + width: 500px; + height: 500px; + image-rendering: auto; + } + </style> +</head> +<body> + <canvas id="can" width="50" height="50"></canvas> +<script> + +var outputCanvas = document.getElementById("can"); +var outputContext = outputCanvas.getContext("2d"); +outputContext.fillRect(10, 10, 30, 30); + +</script> +</body> +</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAuto.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAuto.html new file mode 100644 index 0000000..66d006e --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAuto.html
@@ -0,0 +1,55 @@ +<!doctype html> +<html> + <head> + <title>Test if the users can change Image Rendering Quality in Offscreen Canvas</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <style type="text/css"> +#can { + width: 500px; + height: 500px; + image-rendering: pixelated; +} + </style> + </head> + <body> + <canvas id="can" width="50" height="50"></canvas> + <script> +const c2 = document.getElementById("can"); +const offscreen_canvas = c2.transferControlToOffscreen(); +const ctx_o = offscreen_canvas.getContext('2d'); + +c2.style.imageRendering = "auto"; + +ctx_o.clearRect(0, 0, 50, 50); +ctx_o.fillRect(10, 10, 30, 30); + +function waitForCanvasToDraw() { + return new Promise(resolve => { + const testPixel = function() { + const d = ctx_o.getImageData(20, 20, 1, 1); + if (d.data[0] == 0 && d.data[3] == 255) { + setTimeout(resolve, 2000); + } else { + requestAnimationFrame(testPixel); + } + } + testPixel(); + }) +} + +if (window.testRunner) { + testRunner.waitUntilDone(); +} +waitForCanvasToDraw().then(() => { + if (window.testRunner) { + testRunner.notifyDone(); + } +}).catch(err => { + testRunner.notifyDone(); + throw err; +}); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAutoWorker-expected.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAutoWorker-expected.html new file mode 100644 index 0000000..644a610 --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAutoWorker-expected.html
@@ -0,0 +1,22 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + #can { + width: 500px; + height: 500px; + image-rendering: auto; + } + </style> +</head> +<body> + <canvas id="can" width="50" height="50"></canvas> +<script> + +var outputCanvas = document.getElementById("can"); +var outputContext = outputCanvas.getContext("2d"); +outputContext.fillRect(10, 10, 30, 30); + +</script> +</body> +</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAutoWorker.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAutoWorker.html new file mode 100644 index 0000000..31c97fd --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingAutoWorker.html
@@ -0,0 +1,89 @@ +<!DOCTYPE html> +<title>Test using a placeholder canvas as an image source.</title> +<head> + <title>Test if the users can change Image Rendering Quality in Offscreen Canvas</title> + <style type="text/css"> +#can { +width: 500px; +height: 500px; +image-rendering: pixelated; +} + </style> +</head> + +<body> + <canvas id="can" width="50" height="50"></canvas> + +<script id='myWorker' type='text/worker'> + +var ctx_o; +self.onmessage = function(msg) { + ctx_o = msg.data.getContext('2d'); + draw(); +}; + +function draw() { + ctx_o.clearRect(0, 0, 50, 50); + ctx_o.fillRect(10, 10, 30, 30); + const d = ctx_o.getImageData(20, 20, 1, 1); + if (d.data[0] == 0 && d.data[3] == 255) { + self.postMessage("done"); + } else { + requestAnimationFrame(draw); + } +} +</script> + +<script> +var canvas = document.getElementById("can"); +canvas.width = 50; +canvas.height = 50; +var offscreen = canvas.transferControlToOffscreen(); + +var blob = new Blob([document.getElementById('myWorker').textContent]); +var worker = new Worker(URL.createObjectURL(blob)); +canvas.style.imageRendering = "auto"; +worker.postMessage(offscreen, [offscreen]); + +function waitForCanvasToDraw() { + return new Promise(resolve => { + var i = 0; + const testPixel = function() { + canvas.toBlob(blob => { + createImageBitmap(blob).then(image => { + if (verifyImage(image, "verify if image is drawn on offscreencanvas.")) { + setTimeout(resolve, 2000); + } else { + requestAnimationFrame(testPixel); + } + }) + }); + } + testPixel(); + }) +} + +function verifyImage(image, description) { + var testCanvas = document.createElement('canvas'); + var testCtx = testCanvas.getContext('2d'); + testCtx.drawImage(image, 0, 0); + const d = testCtx.getImageData(20, 20, 1, 1); + return (d.data[0] == 0 && d.data[3] == 255); +} + +if (window.testRunner) { + testRunner.waitUntilDone(); +} + +waitForCanvasToDraw().then(() => { + if (window.testRunner) { + testRunner.notifyDone(); + } +}).catch(err => { + testRunner.notifyDone(); + throw err; +}); + +</script> + +</body> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelated-expected.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelated-expected.html new file mode 100644 index 0000000..ee57b481 --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelated-expected.html
@@ -0,0 +1,22 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + #can { + width: 500px; + height: 500px; + image-rendering: pixelated; + } + </style> +</head> +<body> + <canvas id="can" width="50" height="50"></canvas> +<script> + +var outputCanvas = document.getElementById("can"); +var outputContext = outputCanvas.getContext("2d"); +outputContext.fillRect(10, 10, 30, 30); + +</script> +</body> +</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelated.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelated.html new file mode 100644 index 0000000..73819cc --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelated.html
@@ -0,0 +1,55 @@ +<!doctype html> +<html> + <head> + <title>Test if the users can change Image Rendering Quality in Offscreen Canvas</title> + <script src="/resources/testharness.js"></script> + <script src="/resources/testharnessreport.js"></script> + <style type="text/css"> +#can { + width: 500px; + height: 500px; + image-rendering: auto; +} + </style> + </head> + <body> + <canvas id="can" width="50" height="50"></canvas> + <script> +const c2 = document.getElementById("can"); +const offscreen_canvas = c2.transferControlToOffscreen(); +const ctx_o = offscreen_canvas.getContext('2d'); + +c2.style.imageRendering = "pixelated"; + +ctx_o.clearRect(0, 0, 50, 50); +ctx_o.fillRect(10, 10, 30, 30); + +function waitForCanvasToDraw() { + return new Promise(resolve => { + const testPixel = function() { + const d = ctx_o.getImageData(20, 20, 1, 1); + if (d.data[0] == 0 && d.data[3] == 255) { + setTimeout(resolve, 2000); + } else { + requestAnimationFrame(testPixel); + } + } + testPixel(); + }) +} + +if (window.testRunner) { + testRunner.waitUntilDone(); +} +waitForCanvasToDraw().then(() => { + if (window.testRunner) { + testRunner.notifyDone(); + } +}).catch(err => { + testRunner.notifyDone(); + throw err; +}); + +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelatedWorker-expected.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelatedWorker-expected.html new file mode 100644 index 0000000..ee57b481 --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelatedWorker-expected.html
@@ -0,0 +1,22 @@ +<!doctype html> +<html> +<head> + <style type="text/css"> + #can { + width: 500px; + height: 500px; + image-rendering: pixelated; + } + </style> +</head> +<body> + <canvas id="can" width="50" height="50"></canvas> +<script> + +var outputCanvas = document.getElementById("can"); +var outputContext = outputCanvas.getContext("2d"); +outputContext.fillRect(10, 10, 30, 30); + +</script> +</body> +</html> \ No newline at end of file
diff --git a/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelatedWorker.html b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelatedWorker.html new file mode 100644 index 0000000..08b6d00 --- /dev/null +++ b/third_party/blink/web_tests/virtual/gpu/fast/canvas/OffscreenCanvasImageRenderingPixelatedWorker.html
@@ -0,0 +1,89 @@ +<!DOCTYPE html> +<title>Test using a placeholder canvas as an image source.</title> +<head> + <title>Test if the users can change Image Rendering Quality in Offscreen Canvas</title> + <style type="text/css"> +#can { +width: 500px; +height: 500px; +image-rendering: auto; +} + </style> +</head> + +<body> + <canvas id="can" width="50" height="50"></canvas> + +<script id='myWorker' type='text/worker'> + +var ctx_o; +self.onmessage = function(msg) { + ctx_o = msg.data.getContext('2d'); + draw(); +}; + +function draw() { + ctx_o.clearRect(0, 0, 50, 50); + ctx_o.fillRect(10, 10, 30, 30); + const d = ctx_o.getImageData(20, 20, 1, 1); + if (d.data[0] == 0 && d.data[3] == 255) { + self.postMessage("done"); + } else { + requestAnimationFrame(draw); + } +} +</script> + +<script> +var canvas = document.getElementById("can"); +canvas.width = 50; +canvas.height = 50; +var offscreen = canvas.transferControlToOffscreen(); + +var blob = new Blob([document.getElementById('myWorker').textContent]); +var worker = new Worker(URL.createObjectURL(blob)); +canvas.style.imageRendering = "pixelated"; +worker.postMessage(offscreen, [offscreen]); + +function waitForCanvasToDraw() { + return new Promise(resolve => { + var i = 0; + const testPixel = function() { + canvas.toBlob(blob => { + createImageBitmap(blob).then(image => { + if (verifyImage(image, "verify if image is drawn on offscreencanvas.")) { + setTimeout(resolve, 2000); + } else { + requestAnimationFrame(testPixel); + } + }) + }); + } + testPixel(); + }) +} + +function verifyImage(image, description) { + var testCanvas = document.createElement('canvas'); + var testCtx = testCanvas.getContext('2d'); + testCtx.drawImage(image, 0, 0); + const d = testCtx.getImageData(20, 20, 1, 1); + return (d.data[0] == 0 && d.data[3] == 255); +} + +if (window.testRunner) { + testRunner.waitUntilDone(); +} + +waitForCanvasToDraw().then(() => { + if (window.testRunner) { + testRunner.notifyDone(); + } +}).catch(err => { + testRunner.notifyDone(); + throw err; +}); + +</script> + +</body> \ No newline at end of file
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium index f3d72b10..559271e6 100644 --- a/third_party/crashpad/README.chromium +++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@ Short Name: crashpad URL: https://crashpad.chromium.org/ Version: unknown -Revision: 27322abb7ec40f46020f93b3814c19f77ea2ccfb +Revision: bd1aa246ca185519dea0af1c5ca11656c41b0c80 License: Apache 2.0 License File: crashpad/LICENSE Security Critical: yes
diff --git a/third_party/crashpad/crashpad/BUILD.gn b/third_party/crashpad/crashpad/BUILD.gn index d1a2b72..b1294cf 100644 --- a/third_party/crashpad/crashpad/BUILD.gn +++ b/third_party/crashpad/crashpad/BUILD.gn
@@ -23,14 +23,18 @@ if (crashpad_is_in_chromium || crashpad_is_in_fuchsia) { test("crashpad_tests") { deps = [ - "client:client_test", - "handler:handler_test", - "minidump:minidump_test", - "snapshot:snapshot_test", "test:gmock_main", "test:test_test", - "util:util_test", ] + if (!crashpad_is_ios) { + deps += [ + "client:client_test", + "handler:handler_test", + "minidump:minidump_test", + "snapshot:snapshot_test", + "util:util_test", + ] + } } if (crashpad_is_in_fuchsia) { @@ -135,6 +139,9 @@ "client:client_test", "test:gmock_main", ] + if (crashpad_is_ios) { + deps -= [ "client:client_test" ] + } } test("crashpad_handler_test") { @@ -142,6 +149,9 @@ "handler:handler_test", "test:gtest_main", ] + if (crashpad_is_ios) { + deps -= [ "handler:handler_test" ] + } } test("crashpad_minidump_test") { @@ -149,6 +159,9 @@ "minidump:minidump_test", "test:gtest_main", ] + if (crashpad_is_ios) { + deps -= [ "minidump:minidump_test" ] + } } test("crashpad_snapshot_test") { @@ -156,6 +169,9 @@ "snapshot:snapshot_test", "test:gtest_main", ] + if (crashpad_is_ios) { + deps -= [ "snapshot:snapshot_test" ] + } } test("crashpad_test_test") { @@ -170,5 +186,8 @@ "test:gmock_main", "util:util_test", ] + if (crashpad_is_ios) { + deps -= [ "util:util_test" ] + } } }
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS index 90c103d..4cf8825 100644 --- a/third_party/crashpad/crashpad/DEPS +++ b/third_party/crashpad/crashpad/DEPS
@@ -33,7 +33,7 @@ '8048ece6c16c91acfe0d36d1d3cc0890ab6e945c', 'crashpad/third_party/mini_chromium/mini_chromium': Var('chromium_git') + '/chromium/mini_chromium@' + - '2298dbe9d0b3213720ac0e5418ad0013a19aeb5d', + 'cdab1e6263ec7f3f61763efc1dac863f8dc07c80', 'crashpad/third_party/libfuzzer/src': Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' + 'fda403cf93ecb8792cb1d061564d89a6553ca020',
diff --git a/third_party/crashpad/crashpad/build/BUILD.gn b/third_party/crashpad/crashpad/build/BUILD.gn index 0ef1127f..bc77bc8 100644 --- a/third_party/crashpad/crashpad/build/BUILD.gn +++ b/third_party/crashpad/crashpad/build/BUILD.gn
@@ -45,7 +45,26 @@ "-fsanitize=fuzzer", ] - ldflags = [ - "-fsanitize=address", - ] + ldflags = [ "-fsanitize=address" ] +} + +if (crashpad_is_ios) { + group("ios_enable_arc") { + if (crashpad_is_in_chromium) { + public_configs = [ "//build/config/compiler:enable_arc" ] + } else if (crashpad_is_standalone) { + public_configs = + [ "//third_party/mini_chromium/mini_chromium/build:ios_enable_arc" ] + } + } + + group("ios_xctest") { + if (crashpad_is_in_chromium) { + public_configs = [ "//build/config/ios:xctest_config" ] + } else if (crashpad_is_standalone) { + public_configs = [ + "//third_party/mini_chromium/mini_chromium/build/ios:xctest_config", + ] + } + } }
diff --git a/third_party/crashpad/crashpad/build/crashpad_buildconfig.gni b/third_party/crashpad/crashpad/build/crashpad_buildconfig.gni index 7db56d6..e1ef71f2 100644 --- a/third_party/crashpad/crashpad/build/crashpad_buildconfig.gni +++ b/third_party/crashpad/crashpad/build/crashpad_buildconfig.gni
@@ -23,11 +23,10 @@ } } -assert(crashpad_dependencies == "chromium" || - crashpad_dependencies == "fuchsia" || - crashpad_dependencies == "standalone" || - crashpad_dependencies == "external" || - crashpad_dependencies == "dart") +assert( + crashpad_dependencies == "chromium" || crashpad_dependencies == "fuchsia" || + crashpad_dependencies == "standalone" || + crashpad_dependencies == "external" || crashpad_dependencies == "dart") crashpad_is_in_chromium = crashpad_dependencies == "chromium" crashpad_is_in_fuchsia = crashpad_dependencies == "fuchsia" @@ -37,6 +36,7 @@ if (crashpad_is_in_chromium) { crashpad_is_mac = is_mac + crashpad_is_ios = is_ios crashpad_is_win = is_win crashpad_is_linux = is_linux crashpad_is_android = is_android @@ -57,6 +57,7 @@ import("../third_party/mini_chromium/mini_chromium/build/platform.gni") } crashpad_is_mac = mini_chromium_is_mac + crashpad_is_ios = mini_chromium_is_ios crashpad_is_win = mini_chromium_is_win crashpad_is_linux = mini_chromium_is_linux crashpad_is_android = mini_chromium_is_android
diff --git a/third_party/crashpad/crashpad/test/BUILD.gn b/third_party/crashpad/crashpad/test/BUILD.gn index 7f44863..5159744b 100644 --- a/third_party/crashpad/crashpad/test/BUILD.gn +++ b/third_party/crashpad/crashpad/test/BUILD.gn
@@ -43,13 +43,36 @@ "test_paths.h", ] + if (crashpad_is_ios) { + sources -= [ + "errors.cc", + "errors.h", + "file.cc", + "file.h", + "filesystem.cc", + "filesystem.h", + "multiprocess.h", + "multiprocess_exec.cc", + "multiprocess_exec.h", + "process_type.cc", + "process_type.h", + "scoped_guarded_page.h", + "scoped_module_handle.cc", + "scoped_module_handle.h", + "scoped_temp_dir.cc", + "scoped_temp_dir.h", + "test_paths.cc", + "test_paths.h", + ] + } + if (crashpad_is_posix || crashpad_is_fuchsia) { sources += [ "scoped_guarded_page_posix.cc", "scoped_temp_dir_posix.cc", ] - if (!crashpad_is_fuchsia) { + if (!crashpad_is_fuchsia && !crashpad_is_ios) { sources += [ "multiprocess_exec_posix.cc", "multiprocess_posix.cc", @@ -118,6 +141,13 @@ "../util", ] + if (crashpad_is_ios) { + deps -= [ + "../compat", + "../util", + ] + } + if (crashpad_is_mac) { libs = [ "bsm" ] deps += [ @@ -152,9 +182,18 @@ "test_paths_test.cc", ] + if (crashpad_is_ios) { + sources -= [ + "multiprocess_exec_test.cc", + "scoped_guarded_page_test.cc", + "scoped_temp_dir_test.cc", + "test_paths_test.cc", + ] + } + # TODO(crbug.com/812974): Remove !crashpad_is_fuchsia when Fuchsia is no # longer treated as a posix platform. - if (crashpad_is_posix && !crashpad_is_fuchsia) { + if (crashpad_is_posix && !crashpad_is_fuchsia && !crashpad_is_ios) { sources += [ "multiprocess_posix_test.cc" ] } @@ -181,16 +220,27 @@ data_deps = [ ":crashpad_test_test_multiprocess_exec_test_child", ] + + if (crashpad_is_ios) { + deps -= [ + "../compat", + "../util", + ] + + data_deps -= [ ":crashpad_test_test_multiprocess_exec_test_child" ] + } } -crashpad_executable("crashpad_test_test_multiprocess_exec_test_child") { - sources = [ - "multiprocess_exec_test_child.cc", - ] +if (!crashpad_is_ios) { + crashpad_executable("crashpad_test_test_multiprocess_exec_test_child") { + sources = [ + "multiprocess_exec_test_child.cc", + ] - deps = [ - "../third_party/mini_chromium:base", - ] + deps = [ + "../third_party/mini_chromium:base", + ] + } } static_library("gmock_main") {
diff --git a/third_party/crashpad/crashpad/test/gtest_death.h b/third_party/crashpad/crashpad/test/gtest_death.h index 69f6361e..f205a2f 100644 --- a/third_party/crashpad/crashpad/test/gtest_death.h +++ b/third_party/crashpad/crashpad/test/gtest_death.h
@@ -25,7 +25,7 @@ //! \file -#if defined(OS_MACOSX) || DOXYGEN +#if (defined(OS_MACOSX) && !defined(OS_IOS)) || DOXYGEN //! \brief Wraps the gtest `ASSERT_DEATH_IF_SUPPORTED()` macro to make //! assertions about death caused by crashes. @@ -73,14 +73,14 @@ regex); \ } while (false) -#else // OS_MACOSX +#else // OS_MACOSX && !OS_IOS #define ASSERT_DEATH_CRASH(statement, regex) \ ASSERT_DEATH_IF_SUPPORTED(statement, regex) #define EXPECT_DEATH_CRASH(statement, regex) \ EXPECT_DEATH_IF_SUPPORTED(statement, regex) -#endif // OS_MACOSX +#endif // OS_MACOSX && !OS_IOS #if !(!defined(MINI_CHROMIUM_BASE_LOGGING_H_) && \ defined(OFFICIAL_BUILD) && \
diff --git a/third_party/crashpad/crashpad/test/gtest_main.cc b/third_party/crashpad/crashpad/test/gtest_main.cc index 5a54691..e65f921 100644 --- a/third_party/crashpad/crashpad/test/gtest_main.cc +++ b/third_party/crashpad/crashpad/test/gtest_main.cc
@@ -33,6 +33,7 @@ namespace { +#if !defined(OS_IOS) bool GetChildTestFunctionName(std::string* child_func_name) { constexpr size_t arg_length = sizeof(crashpad::test::internal::kChildTestFunction) - 1; @@ -45,17 +46,20 @@ } return false; } +#endif // !OS_IOS } // namespace int main(int argc, char* argv[]) { crashpad::test::InitializeMainArguments(argc, argv); +#if !defined(OS_IOS) std::string child_func_name; if (GetChildTestFunctionName(&child_func_name)) { return crashpad::test::internal::CheckedInvokeMultiprocessChild( child_func_name); } +#endif // !OS_IOS #if defined(CRASHPAD_IS_IN_CHROMIUM)
diff --git a/third_party/crashpad/crashpad/util/BUILD.gn b/third_party/crashpad/crashpad/util/BUILD.gn index d225f1d..0255890 100644 --- a/third_party/crashpad/crashpad/util/BUILD.gn +++ b/third_party/crashpad/crashpad/util/BUILD.gn
@@ -332,6 +332,7 @@ "linux/traits.h", "misc/capture_context_linux.S", "misc/paths_linux.cc", + "misc/time_linux.cc", "posix/process_info_linux.cc", "process/process_memory_linux.cc", "process/process_memory_linux.h",
diff --git a/third_party/crashpad/crashpad/util/linux/proc_stat_reader.cc b/third_party/crashpad/crashpad/util/linux/proc_stat_reader.cc index 88658f5..dd663d6c 100644 --- a/third_party/crashpad/crashpad/util/linux/proc_stat_reader.cc +++ b/third_party/crashpad/crashpad/util/linux/proc_stat_reader.cc
@@ -85,7 +85,8 @@ return ReadTimeAtIndex(14, system_time); } -bool ProcStatReader::StartTime(timeval* start_time) const { +bool ProcStatReader::StartTime(const timeval& boot_time, + timeval* start_time) const { INITIALIZATION_STATE_DCHECK_VALID(initialized_); timeval time_after_boot; @@ -93,24 +94,7 @@ return false; } - timespec uptime; - if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { - PLOG(ERROR) << "clock_gettime"; - return false; - } - - timespec current_time; - if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { - PLOG(ERROR) << "clock_gettime"; - return false; - } - - timespec boot_time_ts; - SubtractTimespec(current_time, uptime, &boot_time_ts); - timeval boot_time_tv; - TimespecToTimeval(boot_time_ts, &boot_time_tv); - timeradd(&boot_time_tv, &time_after_boot, start_time); - + timeradd(&boot_time, &time_after_boot, start_time); return true; }
diff --git a/third_party/crashpad/crashpad/util/linux/proc_stat_reader.h b/third_party/crashpad/crashpad/util/linux/proc_stat_reader.h index c0b30520..6eae8fb 100644 --- a/third_party/crashpad/crashpad/util/linux/proc_stat_reader.h +++ b/third_party/crashpad/crashpad/util/linux/proc_stat_reader.h
@@ -60,11 +60,12 @@ //! \brief Determines the target thread’s start time. //! + //! \param[in] boot_time The kernel boot time. //! \param[out] start_time The time that the thread started. //! //! \return `true` on success, with \a start_time set. Otherwise, `false` with //! a message logged. - bool StartTime(timeval* start_time) const; + bool StartTime(const timeval& boot_time, timeval* start_time) const; private: bool FindColumn(int index, const char** column) const;
diff --git a/third_party/crashpad/crashpad/util/linux/proc_stat_reader_test.cc b/third_party/crashpad/crashpad/util/linux/proc_stat_reader_test.cc index 1a8a1afb9..01b9afd 100644 --- a/third_party/crashpad/crashpad/util/linux/proc_stat_reader_test.cc +++ b/third_party/crashpad/crashpad/util/linux/proc_stat_reader_test.cc
@@ -19,9 +19,9 @@ #include <unistd.h> #include "base/logging.h" -#include "build/build_config.h" #include "gtest/gtest.h" #include "test/linux/fake_ptrace_connection.h" +#include "util/misc/time.h" #include "util/thread/thread.h" namespace crashpad { @@ -35,8 +35,13 @@ ProcStatReader stat; ASSERT_TRUE(stat.Initialize(&connection, getpid())); + timespec boot_time_ts; + ASSERT_TRUE(GetBootTime(&boot_time_ts)); + timeval boot_time; + TimespecToTimeval(boot_time_ts, &boot_time); + timeval start_time; - ASSERT_TRUE(stat.StartTime(&start_time)); + ASSERT_TRUE(stat.StartTime(boot_time, &start_time)); time_t now; time(&now); @@ -57,36 +62,38 @@ return syscall(SYS_gettid); } -void GetStartTime(timeval* start_time) { +void GetStartTime(const timeval& boot_time, timeval* start_time) { FakePtraceConnection connection; ASSERT_TRUE(connection.Initialize(getpid())); ProcStatReader stat; ASSERT_TRUE(stat.Initialize(&connection, gettid())); - ASSERT_TRUE(stat.StartTime(start_time)); + ASSERT_TRUE(stat.StartTime(boot_time, start_time)); } class StatTimeThread : public Thread { public: - StatTimeThread(timeval* start_time) : start_time_(start_time) {} + StatTimeThread(const timeval& boot_time, timeval* start_time) + : boot_time_(boot_time), start_time_(start_time) {} private: - void ThreadMain() override { GetStartTime(start_time_); } + void ThreadMain() override { GetStartTime(boot_time_, start_time_); } + + const timeval& boot_time_; timeval* start_time_; }; -// TODO(https://crbug.com/1016765): Flaky on Linux. -#if defined(OS_LINUX) -#define MAYBE_Threads DISABLED_Threads -#else -#define MAYBE_Threads Threads -#endif -TEST(ProcStatReader, MAYBE_Threads) { +TEST(ProcStatReader, Threads) { + timespec boot_time_ts; + ASSERT_TRUE(GetBootTime(&boot_time_ts)); + timeval boot_time; + TimespecToTimeval(boot_time_ts, &boot_time); + timeval main_time; - ASSERT_NO_FATAL_FAILURE(GetStartTime(&main_time)); + ASSERT_NO_FATAL_FAILURE(GetStartTime(boot_time, &main_time)); timeval thread_time; - StatTimeThread thread(&thread_time); + StatTimeThread thread(boot_time, &thread_time); thread.Start(); ASSERT_NO_FATAL_FAILURE(thread.Join()); @@ -96,7 +103,7 @@ time_t thread_sec, suseconds_t thread_usec) { return (thread_sec > main_sec) || - (thread_sec == main_sec && thread_usec > main_usec); + (thread_sec == main_sec && thread_usec >= main_usec); }, main_time.tv_sec, main_time.tv_usec,
diff --git a/third_party/crashpad/crashpad/util/misc/time.h b/third_party/crashpad/crashpad/util/misc/time.h index aabe8e64..dffe1a8a 100644 --- a/third_party/crashpad/crashpad/util/misc/time.h +++ b/third_party/crashpad/crashpad/util/misc/time.h
@@ -69,6 +69,14 @@ #endif // OS_WIN +#if defined(OS_LINUX) || defined(OS_ANDROID) || DOXYGEN +//! \brief Get the kernel boot time. Subsequent calls to this function may +//! return different results due to the system clock being changed or +//! imprecision in measuring the boot time. +//! \return `true` on success. Otherwise, `false` with a message logged. +bool GetBootTime(timespec* ts); +#endif // OS_LINUX || OS_ANDROID || DOXYGEN + } // namespace crashpad #endif // CRASHPAD_UTIL_MISC_TIME_H_
diff --git a/third_party/crashpad/crashpad/util/misc/time_linux.cc b/third_party/crashpad/crashpad/util/misc/time_linux.cc new file mode 100644 index 0000000..bc73533 --- /dev/null +++ b/third_party/crashpad/crashpad/util/misc/time_linux.cc
@@ -0,0 +1,38 @@ +// Copyright 2019 The Crashpad Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "util/misc/time.h" + +#include "base/logging.h" + +namespace crashpad { + +bool GetBootTime(timespec* boot_time) { + timespec uptime; + if (clock_gettime(CLOCK_BOOTTIME, &uptime) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } + + timespec current_time; + if (clock_gettime(CLOCK_REALTIME, ¤t_time) != 0) { + PLOG(ERROR) << "clock_gettime"; + return false; + } + + SubtractTimespec(current_time, uptime, boot_time); + return true; +} + +} // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/posix/process_info_linux.cc b/third_party/crashpad/crashpad/util/posix/process_info_linux.cc index 72a2bd7..3ffd96a 100644 --- a/third_party/crashpad/crashpad/util/posix/process_info_linux.cc +++ b/third_party/crashpad/crashpad/util/posix/process_info_linux.cc
@@ -23,6 +23,7 @@ #include "util/file/string_file.h" #include "util/linux/proc_stat_reader.h" #include "util/misc/lexing.h" +#include "util/misc/time.h" namespace crashpad { @@ -238,7 +239,13 @@ if (!reader.Initialize(connection_, pid_)) { return false; } - if (!reader.StartTime(&start_time_)) { + timespec boot_time_ts; + if (!GetBootTime(&boot_time_ts)) { + return false; + } + timeval boot_time; + TimespecToTimeval(boot_time_ts, &boot_time); + if (!reader.StartTime(boot_time, &start_time_)) { return false; } start_time_initialized_.set_valid();
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp index b9da232..82ba393 100644 --- a/third_party/crashpad/crashpad/util/util.gyp +++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -168,6 +168,7 @@ 'misc/symbolic_constants_common.h', 'misc/time.cc', 'misc/time.h', + 'misc/time_linux.cc', 'misc/time_win.cc', 'misc/tri_state.h', 'misc/uuid.cc',
diff --git a/tools/chrome_proxy/webdriver/video.py b/tools/chrome_proxy/webdriver/video.py index 720975a..653f2a1c 100644 --- a/tools/chrome_proxy/webdriver/video.py +++ b/tools/chrome_proxy/webdriver/video.py
@@ -74,7 +74,7 @@ def testRangeRequest(self): with TestDriver() as t: t.AddChromeArg('--enable-spdy-proxy-auth') - t.LoadURL('http://check.googlezip.net/connect') + t.LoadURL('http://check.googlezip.net/report') time.sleep(2) # wait for page load t.ExecuteJavascript( 'var xhr = new XMLHttpRequest();'
diff --git a/tools/grit/grit/format/minifier.py b/tools/grit/grit/format/minifier.py index 011cbea..9bbb2ad2 100644 --- a/tools/grit/grit/format/minifier.py +++ b/tools/grit/grit/format/minifier.py
@@ -10,19 +10,27 @@ import sys __js_minifier = None - +__css_minifier = None def SetJsMinifier(minifier): global __js_minifier __js_minifier = minifier.split() +def SetCssMinifier(minifier): + global __css_minifier + __css_minifier = minifier.split() def Minify(source, filename): file_type = path.splitext(filename)[1] - if not file_type == '.js' or not __js_minifier: + minifier = None + if file_type == '.js': + minifier = __js_minifier + elif file_type == '.css': + minifier = __css_minifier + if not minifier: return source p = subprocess.Popen( - __js_minifier, + minifier, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
diff --git a/tools/grit/grit/tool/build.py b/tools/grit/grit/tool/build.py index c868f2da..7de2f1a 100644 --- a/tools/grit/grit/tool/build.py +++ b/tools/grit/grit/tool/build.py
@@ -136,6 +136,12 @@ minified Javascript to standard output. A non-zero exit status will be taken as indicating failure. + --css-minifier A command to run the CSS minifier. If not set then CSS won't + be minified. The command should read the original CSS from + standard input, and output the minified CSS to standard + output. A non-zero exit status will be taken as indicating + failure. + --brotli The full path to the brotli executable generated by third_party/brotli/BUILD.gn, required if any entries use compress="brotli". @@ -165,13 +171,14 @@ write_only_new = False depend_on_stamp = False js_minifier = None + css_minifier = None replace_ellipsis = True (own_opts, args) = getopt.getopt( args, 'a:p:o:D:E:f:w:t:', ('depdir=', 'depfile=', 'assert-file-list=', 'help', 'output-all-resource-defines', 'no-output-all-resource-defines', 'no-replace-ellipsis', 'depend-on-stamp', 'js-minifier=', - 'write-only-new=', 'whitelist-support', 'brotli=')) + 'css-minifier=', 'write-only-new=', 'whitelist-support', 'brotli=')) for (key, val) in own_opts: if key == '-a': assert_output_files.append(val) @@ -209,6 +216,8 @@ depend_on_stamp = True elif key == '--js-minifier': js_minifier = val + elif key == '--css-minifier': + css_minifier = val elif key == '--whitelist-support': whitelist_support = True elif key == '--brotli': @@ -235,6 +244,9 @@ if js_minifier: minifier.SetJsMinifier(js_minifier) + if css_minifier: + minifier.SetCssMinifier(css_minifier) + self.write_only_new = write_only_new self.res = grd_reader.Parse(opts.input,
diff --git a/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni index bd45b63..be60d0d 100644 --- a/tools/grit/grit_rule.gni +++ b/tools/grit/grit_rule.gni
@@ -226,6 +226,7 @@ _strip_resource_files = is_android && is_official_build _js_minifier = "//tools/grit/minify_with_uglify.py" +_css_minifier = "//tools/grit/minimize_css.py" grit_resource_id_file = "//tools/gritsettings/resource_ids" grit_info_script = "//tools/grit/grit_info.py" @@ -407,12 +408,16 @@ } if (_strip_resource_files) { js_minifier_command = rebase_path(_js_minifier, root_build_dir) + css_minifier_command = rebase_path(_css_minifier, root_build_dir) args += [ "--js-minifier", js_minifier_command, + "--css-minifier", + css_minifier_command, ] inputs += [ _js_minifier, + _css_minifier, "//third_party/closure_compiler/compiler/compiler.jar", ] }
diff --git a/tools/grit/minimize_css.py b/tools/grit/minimize_css.py new file mode 100755 index 0000000..2c3b8ae --- /dev/null +++ b/tools/grit/minimize_css.py
@@ -0,0 +1,105 @@ +#!/usr/bin/env python +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import re +import sys + +class CSSMinimizer(object): + + INITIAL = 0 + MAYBE_COMMENT_START = 1 + INSIDE_COMMENT = 2 + MAYBE_COMMENT_END = 3 + INSIDE_SINGLE_QUOTE = 4 + INSIDE_SINGLE_QUOTE_ESCAPE = 5 + INSIDE_DOUBLE_QUOTE = 6 + INSIDE_DOUBLE_QUOTE_ESCAPE = 7 + + def __init__(self): + self._output = '' + self._codeblock = '' + + def flush_codeblock(self): + stripped = re.sub(r"\s+", ' ', self._codeblock) + stripped = re.sub(r";?\s*(?P<op>[{};])\s*", r'\g<op>', stripped) + self._output += stripped + self._codeblock = '' + + def parse(self, content): + state = self.INITIAL + for char in content: + if state == self.INITIAL: + if char == '/': + state = self.MAYBE_COMMENT_START + elif char == "'": + self.flush_codeblock() + self._output += char + state = self.INSIDE_SINGLE_QUOTE + elif char == '"': + self.flush_codeblock() + self._output += char + state = self.INSIDE_DOUBLE_QUOTE + else: + self._codeblock += char + elif state == self.MAYBE_COMMENT_START: + if char == '*': + self.flush_codeblock() + state = self.INSIDE_COMMENT + else: + self._codeblock += '/' + char + state = self.INITIAL + elif state == self.INSIDE_COMMENT: + if char == '*': + state = self.MAYBE_COMMENT_END + else: + pass + elif state == self.MAYBE_COMMENT_END: + if char == '/': + state = self.INITIAL + else: + state = self.INSIDE_COMMENT + elif state == self.INSIDE_SINGLE_QUOTE: + if char == '\\': + self._output += char + state = self.INSIDE_SINGLE_QUOTE_ESCAPE + elif char == "'": + self._output += char + state = self.INITIAL + else: + self._output += char + elif state == self.INSIDE_SINGLE_QUOTE_ESCAPE: + self._output += char + state = self.INSIDE_SINGLE_QUOTE + elif state == self.INSIDE_DOUBLE_QUOTE: + if char == '\\': + self._output += char + state = self.INSIDE_DOUBLE_QUOTE_ESCAPE + elif char == '"': + self._output += char + state = self.INITIAL + else: + self._output += char + elif state == self.INSIDE_DOUBLE_QUOTE_ESCAPE: + self._output += char + state = self.INSIDE_DOUBLE_QUOTE + + self.flush_codeblock() + self._output = self._output.strip() + return self._output + + @classmethod + def minimize_css(cls, content): + minimizer = CSSMinimizer() + return minimizer.parse(content) + +def main(): + result = '' + try: + result = CSSMinimizer.minimize_css(sys.stdin.read()) + finally: + print(result) + +if __name__ == '__main__': + main()
diff --git a/third_party/blink/renderer/build/scripts/minimize_css_unittest.py b/tools/grit/minimize_css_unittest.py similarity index 100% rename from third_party/blink/renderer/build/scripts/minimize_css_unittest.py rename to tools/grit/minimize_css_unittest.py
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml index 4ca6a9c..040c482 100644 --- a/tools/metrics/actions/actions.xml +++ b/tools/metrics/actions/actions.xml
@@ -2360,6 +2360,11 @@ <description>Please enter the description of this user action.</description> </action> +<action name="AppList_BackButtonPressed"> + <owner>andrewxu@chromium.org</owner> + <description>User pressed the back button.</description> +</action> + <action name="AppList_ClickOnApp"> <owner>vadimt@chromium.org</owner> <description> @@ -2403,6 +2408,16 @@ <description>CrOS Launcher went from full to peeking state.</description> </action> +<action name="AppList_HomeButtonPressedClamshell"> + <owner>andrewxu@chromium.org</owner> + <description>User pressed the launcher button in clamshell.</description> +</action> + +<action name="AppList_HomeButtonPressedTablet"> + <owner>andrewxu@chromium.org</owner> + <description>User pressed the launcher button in tablet.</description> +</action> + <action name="AppList_HomeLauncherToMRUWindow"> <owner>newcomer@chromium.org</owner> <owner>sammiequon@chromium.org</owner>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index d851843..2afc6959 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -6633,6 +6633,11 @@ <int value="1" label="Latched"/> </enum> +<enum name="BooleanLoadCollided"> + <int value="0" label="Load did not collide"/> + <int value="1" label="Load collided"/> +</enum> + <enum name="BooleanLoaded"> <int value="0" label="Not loaded"/> <int value="1" label="Loaded"/> @@ -6813,6 +6818,11 @@ <int value="1" label="Manual fallback"/> </enum> +<enum name="BooleanPathIsInformative"> + <int value="0" label="Path contains nothing except possibly a slash"/> + <int value="1" label="Path contains text beyond just an opening slash"/> +</enum> + <enum name="BooleanPending"> <int value="0" label="Decided"/> <int value="1" label="Pending"/> @@ -40254,6 +40264,11 @@ <int value="645" label="overscroll-behavior-block"/> <int value="646" label="content-size"/> <int value="647" label="font-optical-sizing"/> + <int value="648" label="intrinsic-block-size"/> + <int value="649" label="intrinsic-height"/> + <int value="650" label="intrinsic-inline-size"/> + <int value="651" label="intrinsic-size"/> + <int value="652" label="intrinsic-width"/> </enum> <enum name="MappedEditingCommands"> @@ -62916,6 +62931,18 @@ <int value="137457845" label="web_history_counter"/> </enum> +<enum name="URLRequestReferrerPolicy"> + <int value="0" label="CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE"/> + <int value="1" + label="REDUCE_REFERRER_GRANULARITY_ON_TRANSITION_CROSS_ORIGIN"/> + <int value="2" label="ORIGIN_ONLY_ON_TRANSITION_CROSS_ORIGIN"/> + <int value="3" label="NEVER_CLEAR_REFERRER"/> + <int value="4" label="ORIGIN"/> + <int value="5" label="CLEAR_REFERRER_ON_TRANSITION_CROSS_ORIGIN"/> + <int value="6" label="ORIGIN_CLEAR_ON_TRANSITION_FROM_SECURE_TO_INSECURE"/> + <int value="7" label="NO_REFERRER"/> +</enum> + <enum name="UrlResolutionResult"> <int value="0" label="Absolute URL"/> <int value="1" label="Resolutions Differ"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index f118ddcc..43d7229 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -21584,7 +21584,7 @@ </summary> </histogram> -<histogram name="ChromeOS.UrlXattrsCount" units="units" expires_after="M80"> +<histogram name="ChromeOS.UrlXattrsCount" units="units" expires_after="M81"> <owner>jorgelo@chromium.org</owner> <owner>tnagel@chromium.org</owner> <summary> @@ -85557,6 +85557,32 @@ <summary>The time spent in closesocket call in UDPSocketWin::Close.</summary> </histogram> +<histogram name="Net.URLRequest.ReferrerHasInformativePath" + enum="BooleanPathIsInformative" expires_after="2020-03-30"> +<!-- Name completed by histogram_suffixes name="ReferrerPolicySameOrigin" --> + + <owner>davidvc@chromium.org</owner> + <owner>kaustubhag@chromium.org</owner> + <summary> + Records for each URLRequest whether its referrer contains more information + than just its origin (this is the case exactly when it has at least one + character apart from a leading slash in its path, e.g. http://example.com/a + but not http://example.com/ nor http://example.com). + </summary> +</histogram> + +<histogram name="Net.URLRequest.ReferrerPolicyForRequest" + enum="URLRequestReferrerPolicy" expires_after="2020-03-30"> +<!-- Name completed by histogram_suffixes name="ReferrerPolicySameOrigin" --> + + <owner>davidvc@chromium.org</owner> + <owner>kaustubhag@chromium.org</owner> + <summary> + Records the distribution of referrer policies provided with outgoing + URLRequests, and whether or not the requests were cross-origin. + </summary> +</histogram> + <histogram name="Net.URLRequest.ReferrerPolicyHeaderPresentOnRedirect" enum="BooleanPresent"> <owner>estark@chromium.org</owner> @@ -97690,6 +97716,16 @@ </summary> </histogram> +<histogram name="OptimizationGuide.PredictionModelStore.OnLoadCollided" + enum="BooleanLoadCollided" expires_after="M85"> + <owner>mcrouse@chromium.org</owner> + <owner>sophiechang@chromium.org</owner> + <summary> + For each load of a prediction model from the OptimizationGuideStore, reports + whether the load collided with an update being made to the store. + </summary> +</histogram> + <histogram name="OptimizationGuide.ProcessHintsResult" enum="OptimizationGuideProcessHintsResult" expires_after="M85"> <owner>dougarnett@chromium.org</owner> @@ -179020,6 +179056,15 @@ <affected-histogram name="SafeBrowsing.ReferrerURLChainSize"/> </histogram_suffixes> +<histogram_suffixes name="ReferrerPolicySameOrigin" separator="."> + <suffix name="CrossOrigin" label="Cross-origin requests."/> + <suffix name="SameOrigin" + label="Same-origin requests (relative to the initiator, if present, and + otherwise the initial referrer URL)."/> + <affected-histogram name="Net.URLRequest.ReferrerHasInformativePath"/> + <affected-histogram name="Net.URLRequest.ReferrerPolicyForRequest"/> +</histogram_suffixes> + <histogram_suffixes name="RelaunchNotificationStyle" separator="."> <suffix name="Recommended" label="The relaunch recommended bubble."/> <suffix name="Required" label="The relaunch required dialog."/>
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml index cc553ec8..292703b 100644 --- a/tools/metrics/rappor/rappor.xml +++ b/tools/metrics/rappor/rappor.xml
@@ -174,27 +174,6 @@ </summary> </rappor-metric> -<rappor-metric name="Plugins.FlashOriginUrl" type="ETLD_PLUS_ONE"> - <owner>wfh@chromium.org</owner> - <summary> - The domain and registry of the top level URL of a page which attempts to - launch a Flash NPAPI or PPAPI plugin, if the client has Flash installed and - enabled. Recorded when the plugin frame appears for each Flash object found - on the page, even if the plugin is click-to-play. - </summary> -</rappor-metric> - -<rappor-metric name="Plugins.FlashUrl" type="ETLD_PLUS_ONE"> - <owner>wfh@chromium.org</owner> - <summary> - The domain and registry of the URL from where Flash SWF or SPL content is - being loaded from, while attempting to launch a Flash (NPAPI or PPAPI) - plugin that is installed and enabled. Recorded when the plugin frame appears - for each Flash object found in the page, even if the plugin is - click-to-play. - </summary> -</rappor-metric> - <rappor-metric name="PowerfulFeatureUse.ETLDPlus1.GetUserMedia.Insecure" type="ETLD_PLUS_ONE"> <owner>guidou@chromium.org</owner>
diff --git a/tools/metrics/ukm/ukm.xml b/tools/metrics/ukm/ukm.xml index 350b00e..6210309 100644 --- a/tools/metrics/ukm/ukm.xml +++ b/tools/metrics/ukm/ukm.xml
@@ -233,20 +233,20 @@ </summary> <metric name="AdBytes"> <summary> - Amount of bytes used to load ad resource on the page. Includes resources - that did not finish, and top-level ads. + Amount of network bytes used to load ad resource on the page. Includes + resources that did not finish, and top-level ads. Measured in kilobytes. </summary> </metric> <metric name="AdBytesPerSecond"> <summary> - Amount of bytes used to load ad resources on the page, per second the page - was alive after commit. + Amount of network bytes used to load ad resources on the page, per second + the page was alive after commit. Measured in kilobytes per second. </summary> </metric> <metric name="AdBytesPerSecondAfterInteractive"> <summary> - Amount of bytes used to load ad resources on the page per second after the - page was interactive. + Amount of network bytes used to load ad resources on the page per second + after the page was interactive. Measured in kilobytes. </summary> </metric> <metric name="AdCpuTime"> @@ -257,20 +257,28 @@ </metric> <metric name="AdJavascriptBytes"> <summary> - Amount of bytes used to load ad resources with a supported javascript mime - type on the page. + Amount of network bytes used to load ad resources with a supported + javascript mime type on the page. Measured in kilobytes. </summary> </metric> <metric name="AdVideoBytes"> <summary> - Amount of bytes used to load ad resources with a video mime type on the - page. + Amount of network bytes used to load ad resources with a video mime type + on the page. Measured in kilobytes. + </summary> + </metric> + <metric name="MainframeAdBytes"> + <summary> + Amount of network bytes used to load ad resources in the main frame. + Includes resources that did not finish but does not include resources in + subframes. Measured in bytes. This is rounded to the nearest exponential + bucket (with a bucket ratio of 1.3). </summary> </metric> <metric name="TotalBytes"> <summary> - Amount of bytes used to load resources on the page. Includes resources - that did not finish. + Amount of network bytes used to load resources on the page. Includes + resources that did not finish. Measured in kilobytes. </summary> </metric> </event>
diff --git a/ui/accessibility/ax_tree.cc b/ui/accessibility/ax_tree.cc index 1e46510..4785ec1 100644 --- a/ui/accessibility/ax_tree.cc +++ b/ui/accessibility/ax_tree.cc
@@ -1847,34 +1847,32 @@ continue; } - int child_level = - child->GetIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel); - - if (child_level < original_level) { - // If a decrease in level occurs after the original node has been - // examined, stop adding to this set. - if (original_node_index < i) - break; - - // If a decrease in level has been detected before the original node - // has been examined, then everything previously added to items actually - // belongs to a different set. Clear items vector. - items.clear(); - continue; - } else if (child_level > original_level) { - continue; - } - - // If role of node is kRadioButton, only add other kRadioButtons. - if (node_is_radio_button && - child->data().role == ax::mojom::Role::kRadioButton) - items.push_back(child); - // Add child to items if role matches with ordered set's role. If role of // node is kRadioButton, don't add items of other roles, even if item role // matches ordered set role. - if (!node_is_radio_button && child->SetRoleMatchesItemRole(ordered_set)) + if ((node_is_radio_button && + child->data().role == ax::mojom::Role::kRadioButton) || + (!node_is_radio_button && child->SetRoleMatchesItemRole(ordered_set))) { + int child_level = + child->GetIntAttribute(ax::mojom::IntAttribute::kHierarchicalLevel); + + if (child_level < original_level) { + // If a decrease in level occurs after the original node has been + // examined, stop adding to this set. + if (original_node_index < i) + break; + + // If a decrease in level has been detected before the original node + // has been examined, then everything previously added to items actually + // belongs to a different set. Clear items vector. + items.clear(); + continue; + } else if (child_level > original_level) { + continue; + } + items.push_back(child); + } // Recurse if there is a generic container, ignored, or unknown. if (child->IsIgnored() ||
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index 4647c4a..91a9610 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -764,31 +764,11 @@ value); } -#if defined(ATK_212) -void SetValue(AtkValue* atk_value, const double new_value) { - g_return_if_fail(ATK_VALUE(atk_value)); - - AtkObject* atk_object = ATK_OBJECT(atk_value); - AXPlatformNodeAuraLinux* obj = AtkObjectToAXPlatformNodeAuraLinux(atk_object); - if (!obj) - return; - - AXActionData data; - data.action = ax::mojom::Action::kSetValue; - data.value = base::NumberToString(new_value); - obj->GetDelegate()->AccessibilityPerformAction(data); -} -#endif // defined(ATK_212) - void Init(AtkValueIface* iface) { iface->get_current_value = GetCurrentValue; iface->get_maximum_value = GetMaximumValue; iface->get_minimum_value = GetMinimumValue; iface->get_minimum_increment = GetMinimumIncrement; - -#if defined(ATK_212) - iface->set_value = SetValue; -#endif // defined(ATK_212) } const GInterfaceInfo Info = {reinterpret_cast<GInterfaceInitFunc>(Init), @@ -3429,8 +3409,10 @@ // If this is a non-web-content text entry, then we need to trigger text // change signals when the value changes. This is handled by browser // accessibility for web content. - if (IsPlainTextField() && !GetDelegate()->IsWebContent()) + if (IsPlainTextField() || !GetDelegate()->IsWebContent()) { UpdateHypertext(); + return; + } if (!IsRangeValueSupported(GetData())) return;
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc index 3ee9ebb..fe973d51 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux_unittest.cc
@@ -993,66 +993,6 @@ g_object_unref(root_obj); } -#if ATK_CHECK_VERSION(2, 12, 0) -typedef bool (*SetValueFunction)(AtkValue* component, double value); - -TEST_F(AXPlatformNodeAuraLinuxTest, TestAtkValueChangedSignal) { - // There's a chance we may be compiled with a newer version of ATK and then - // run with an older one, so we need to do a runtime check for this method - // that is available in ATK 2.12 instead of linking directly. - SetValueFunction atk_value_set_value = reinterpret_cast<SetValueFunction>( - dlsym(RTLD_DEFAULT, "atk_value_set_value")); - if (!atk_value_set_value) { - LOG(WARNING) << "Skipping TestAtkValueChangedSignal" - " because ATK version < 2.12 detected."; - return; - } - - AXNodeData root; - root.id = 1; - root.role = ax::mojom::Role::kSlider; - root.AddFloatAttribute(ax::mojom::FloatAttribute::kMaxValueForRange, 5.0); - Init(root); - - AtkObject* root_object(GetRootAtkObject()); - ASSERT_TRUE(ATK_IS_OBJECT(root_object)); - ASSERT_TRUE(ATK_IS_VALUE(root_object)); - g_object_ref(root_object); - - bool saw_value_change = false; - g_signal_connect( - root_object, "property-change::accessible-value", - G_CALLBACK(+[](AtkObject*, void* property, bool* saw_value_change) { - *saw_value_change = true; - }), - &saw_value_change); - - atk_value_set_value(ATK_VALUE(root_object), 24.0); - GetRootPlatformNode()->NotifyAccessibilityEvent( - ax::mojom::Event::kValueChanged); - - GValue current_value = G_VALUE_INIT; - atk_value_get_current_value(ATK_VALUE(root_object), ¤t_value); - EXPECT_EQ(G_TYPE_FLOAT, G_VALUE_TYPE(¤t_value)); - EXPECT_EQ(24.0, g_value_get_float(¤t_value)); - EXPECT_TRUE(saw_value_change); - - saw_value_change = false; - atk_value_set_value(ATK_VALUE(root_object), 100.0); - GetRootPlatformNode()->NotifyAccessibilityEvent( - ax::mojom::Event::kValueChanged); - - g_value_unset(¤t_value); - atk_value_get_current_value(ATK_VALUE(root_object), ¤t_value); - EXPECT_EQ(G_TYPE_FLOAT, G_VALUE_TYPE(¤t_value)); - EXPECT_EQ(100.0, g_value_get_float(¤t_value)); - EXPECT_TRUE(saw_value_change); - - g_value_unset(¤t_value); - g_object_unref(root_object); -} -#endif // ATK_CHECK_VERSION(2, 12, 0) - // // AtkHyperlinkImpl interface //
diff --git a/ui/color/BUILD.gn b/ui/color/BUILD.gn index 42f18df..abda7ae0 100644 --- a/ui/color/BUILD.gn +++ b/ui/color/BUILD.gn
@@ -64,8 +64,8 @@ "color_mixer_unittest.cc", "color_provider_unittest.cc", "color_recipe_unittest.cc", + "color_test_ids.h", "color_transform_unittest.cc", - "color_unittest_utils.h", "run_all_unittests.cc", ]
diff --git a/ui/color/color_mixer_unittest.cc b/ui/color/color_mixer_unittest.cc index 34eddcf..f2ad20f1 100644 --- a/ui/color/color_mixer_unittest.cc +++ b/ui/color/color_mixer_unittest.cc
@@ -6,7 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/color/color_recipe.h" -#include "ui/color/color_unittest_utils.h" +#include "ui/color/color_test_ids.h" #include "ui/gfx/color_palette.h" namespace ui {
diff --git a/ui/color/color_provider_unittest.cc b/ui/color/color_provider_unittest.cc index eda0fa5..c094c03 100644 --- a/ui/color/color_provider_unittest.cc +++ b/ui/color/color_provider_unittest.cc
@@ -5,7 +5,7 @@ #include "ui/color/color_provider.h" #include "testing/gtest/include/gtest/gtest.h" -#include "ui/color/color_unittest_utils.h" +#include "ui/color/color_test_ids.h" #include "ui/gfx/color_palette.h" namespace ui {
diff --git a/ui/color/color_recipe_unittest.cc b/ui/color/color_recipe_unittest.cc index 9974b06c..2550214 100644 --- a/ui/color/color_recipe_unittest.cc +++ b/ui/color/color_recipe_unittest.cc
@@ -7,7 +7,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/color/color_mixer.h" #include "ui/color/color_set.h" -#include "ui/color/color_unittest_utils.h" +#include "ui/color/color_test_ids.h" #include "ui/gfx/color_palette.h" namespace ui {
diff --git a/ui/color/color_unittest_utils.h b/ui/color/color_test_ids.h similarity index 82% rename from ui/color/color_unittest_utils.h rename to ui/color/color_test_ids.h index 40c5b87..a79c216e 100644 --- a/ui/color/color_unittest_utils.h +++ b/ui/color/color_test_ids.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef UI_COLOR_COLOR_UNITTEST_UTILS_H_ -#define UI_COLOR_COLOR_UNITTEST_UTILS_H_ +#ifndef UI_COLOR_COLOR_TEST_IDS_H_ +#define UI_COLOR_COLOR_TEST_IDS_H_ #include "ui/color/color_id.h" @@ -33,4 +33,4 @@ } // namespace ui -#endif // UI_COLOR_COLOR_UNITTEST_UTILS_H_ +#endif // UI_COLOR_COLOR_TEST_IDS_H_
diff --git a/ui/color/color_transform_unittest.cc b/ui/color/color_transform_unittest.cc index 857cdb9..f8cc4a3 100644 --- a/ui/color/color_transform_unittest.cc +++ b/ui/color/color_transform_unittest.cc
@@ -7,7 +7,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/color/color_mixer.h" #include "ui/color/color_recipe.h" -#include "ui/color/color_unittest_utils.h" +#include "ui/color/color_test_ids.h" #include "ui/gfx/color_palette.h" namespace ui {
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc index 46c9ae5..3d4f710 100644 --- a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc +++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.cc
@@ -8,6 +8,8 @@ #include <utility> #include "base/feature_list.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" #include "base/time/time.h" #include "ui/events/ozone/evdev/event_device_info.h" #include "ui/events/ozone/evdev/touch_filter/heuristic_stylus_palm_detection_filter.h" @@ -25,6 +27,10 @@ const base::Feature kEnableNeuralPalmDetectionFilter{ "EnableNeuralPalmDetectionFilter", base::FEATURE_DISABLED_BY_DEFAULT}; +EVENTS_OZONE_EVDEV_EXPORT +extern const base::FeatureParam<std::string> kNeuralPalmRadiusPolynomial{ + &kEnableNeuralPalmDetectionFilter, "neural_palm_radius_polynomial", ""}; + const base::FeatureParam<double> kHeuristicCancelThresholdSeconds{ &kEnableHeuristicPalmDetectionFilter, "heuristic_palm_cancel_threshold_seconds", 0.4}; @@ -36,15 +42,38 @@ const base::FeatureParam<int> kHeuristicStrokeCount{ &kEnableHeuristicPalmDetectionFilter, "heuristic_palm_stroke_count", 0}; +namespace internal { + +std::vector<float> ParseRadiusPolynomial(const std::string& radius_string) { + std::vector<std::string> split_radii = base::SplitString( + radius_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + std::vector<float> return_value; + for (const std::string& unparsed : split_radii) { + double item; + if (!base::StringToDouble(unparsed, &item) && !std::isnan(item)) { + LOG(DFATAL) << "Unable to parse " << unparsed + << " to a floating point; Returning empty."; + return {}; + } + return_value.push_back(item); + } + return return_value; +} + +} // namespace internal + std::unique_ptr<PalmDetectionFilter> CreatePalmDetectionFilter( const EventDeviceInfo& devinfo, SharedPalmDetectionFilterState* shared_palm_state) { if (base::FeatureList::IsEnabled(kEnableNeuralPalmDetectionFilter) && NeuralStylusPalmDetectionFilter:: CompatibleWithNeuralStylusPalmDetectionFilter(devinfo)) { + std::vector<float> radius_polynomial = + internal::ParseRadiusPolynomial(kNeuralPalmRadiusPolynomial.Get()); // Theres only one model right now. std::unique_ptr<NeuralStylusPalmDetectionFilterModel> model = - std::make_unique<OneDeviceTrainNeuralStylusPalmDetectionFilterModel>(); + std::make_unique<OneDeviceTrainNeuralStylusPalmDetectionFilterModel>( + radius_polynomial); return std::make_unique<NeuralStylusPalmDetectionFilter>( devinfo, std::move(model), shared_palm_state); }
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h index 3afe8059..96c87c5 100644 --- a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h +++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory.h
@@ -25,6 +25,9 @@ extern const base::Feature kEnableNeuralPalmDetectionFilter; EVENTS_OZONE_EVDEV_EXPORT +extern const base::FeatureParam<std::string> kNeuralPalmRadiusPolynomial; + +EVENTS_OZONE_EVDEV_EXPORT extern const base::FeatureParam<double> kHeuristicCancelThresholdSeconds; EVENTS_OZONE_EVDEV_EXPORT @@ -37,6 +40,13 @@ CreatePalmDetectionFilter(const EventDeviceInfo& devinfo, SharedPalmDetectionFilterState* shared_palm_state); +namespace internal { +// In a named namespace for testing. + +EVENTS_OZONE_EVDEV_EXPORT std::vector<float> ParseRadiusPolynomial( + const std::string& radius_string); +} // namespace internal + } // namespace ui #endif // UI_EVENTS_OZONE_EVDEV_TOUCH_FILTER_PALM_DETECTION_FILTER_FACTORY_H_
diff --git a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc index f17260ec..bb52e22 100644 --- a/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc +++ b/ui/events/ozone/evdev/touch_filter/palm_detection_filter_factory_unittest.cc
@@ -42,6 +42,9 @@ DISALLOW_COPY_AND_ASSIGN(PalmDetectionFilterFactoryTest); }; +class PalmDetectionFilterFactoryDeathTest + : public PalmDetectionFilterFactoryTest {}; + TEST_F(PalmDetectionFilterFactoryTest, AllDisabled) { scoped_feature_list_->InitWithFeatures( {}, {ui::kEnableHeuristicPalmDetectionFilter, @@ -114,4 +117,32 @@ ASSERT_EQ(NeuralStylusPalmDetectionFilter::kFilterName, palm_filter->FilterNameForTesting()); } + +TEST_F(PalmDetectionFilterFactoryTest, ParseTest) { + EXPECT_EQ(std::vector<float>(), internal::ParseRadiusPolynomial("")); + // Note we test for whitespace trimming. + EXPECT_EQ(std::vector<float>({3.7, 2.91, 15.19191}), + internal::ParseRadiusPolynomial("3.7, 2.91, 15.19191 ")); +} + +TEST_F(PalmDetectionFilterFactoryDeathTest, BadParseRecovery) { + // in debug, die. In non debug, expect {} + EXPECT_DEBUG_DEATH(EXPECT_EQ(std::vector<float>(), + internal::ParseRadiusPolynomial("cheese")), + "Unable to parse.*cheese"); +} + +TEST_F(PalmDetectionFilterFactoryDeathTest, BadNeuralParamParse) { + scoped_feature_list_->InitWithFeaturesAndParameters( + {base::test::ScopedFeatureList::FeatureAndParams( + ui::kEnableNeuralPalmDetectionFilter, + { + {"neural_palm_radius_polynomial", "1.0,chicken"}, + })}, + {ui::kEnableHeuristicPalmDetectionFilter}); + EXPECT_DEBUG_DEATH(CreatePalmDetectionFilter(nocturne_touchscreen_info_, + &shared_palm_state_), + "Unable to parse.*chicken"); +} + } // namespace ui
diff --git a/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.cc b/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.cc index cc141787..e84b9f9 100644 --- a/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.cc +++ b/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.cc
@@ -59,4 +59,11 @@ config_.heuristic_palm_area_limit = 400.0f; } +OneDeviceTrainNeuralStylusPalmDetectionFilterModel:: + OneDeviceTrainNeuralStylusPalmDetectionFilterModel( + const std::vector<float>& radius_poly) + : OneDeviceTrainNeuralStylusPalmDetectionFilterModel() { + config_.radius_polynomial_resize = radius_poly; +} + } // namespace ui
diff --git a/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h b/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h index f8f3ab9..1b974d2 100644 --- a/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h +++ b/ui/events/ozone/evdev/touch_filter/palm_model/onedevice_train_palm_detection_filter_model.h
@@ -20,7 +20,8 @@ : public NeuralStylusPalmDetectionFilterModel { public: OneDeviceTrainNeuralStylusPalmDetectionFilterModel(); - + explicit OneDeviceTrainNeuralStylusPalmDetectionFilterModel( + const std::vector<float>& radius_poly); float Inference(const std::vector<float>& features) const override; const NeuralStylusPalmDetectionFilterModelConfig& config() const override;
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css index f4dc935a..66005ab1 100644 --- a/ui/file_manager/file_manager/foreground/css/file_manager.css +++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -238,6 +238,12 @@ background: -webkit-image-set( url(../images/files/ui/eject.png) 1x, url(../images/files/ui/2x/eject.png) 2x) no-repeat center; + border-style: none; + box-shadow: none; + min-width: 16px; + outline-color: rgb(77, 144, 254); + outline-width: 1px; + padding: 10px; } #directory-tree .tree-row[selected] > .root-eject { @@ -246,6 +252,10 @@ url(../images/files/ui/2x/eject_active.png) 2x); } +#directory-tree .tree-row > .root-eject:active { + outline-width: 0; +} + #directory-tree .root-item[disabled] { opacity: 0.5; pointer-events: none;
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js index 93bb5833..0062610 100644 --- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js +++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -703,17 +703,12 @@ * @private */ setupEjectButton_(rowElement) { - const ejectButton = document.createElement('button'); + const ejectButton = document.createElement('cr-button'); ejectButton.className = 'root-eject align-right-icon'; ejectButton.setAttribute('aria-label', str('UNMOUNT_DEVICE_BUTTON_LABEL')); ejectButton.setAttribute('tabindex', '0'); - - // Add paper-ripple effect on the eject button. - const ripple = document.createElement('paper-ripple'); - ripple.setAttribute('fit', ''); - ripple.className = 'circle recenteringTouch'; - ejectButton.appendChild(ripple); + ejectButton.circleRipple = true; // Block mouse handlers, handle click. ejectButton.addEventListener('mouseup', (event) => {
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js index 535eb51..677920db 100644 --- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js +++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -869,7 +869,7 @@ // Wait for the eject button to appear. const ejectButtonQuery = - ['#directory-tree [entry-label="archive.zip"] button.root-eject']; + ['#directory-tree [entry-label="archive.zip"] .root-eject']; await remoteCall.waitForElement(appId, ejectButtonQuery); // Focus on the eject button.
diff --git a/ui/webui/resources/js/assert.js b/ui/webui/resources/js/assert.js index 2befddb..7bb03af 100644 --- a/ui/webui/resources/js/assert.js +++ b/ui/webui/resources/js/assert.js
@@ -15,6 +15,7 @@ * @param {string=} opt_message A message to show on failure. * @return {T} A non-null |condition|. * @closurePrimitive {asserts.truthy} + * @suppress {reportUnknownTypes} because T is not sufficiently constrained. */ /* #export */ function assert(condition, opt_message) { if (!condition) {
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java b/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java index 172c074..0844908 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/BrowserImpl.java
@@ -184,7 +184,9 @@ } mViewController = null; } - mWindowAndroid = null; - mViewController = null; + if (mWindowAndroid != null) { + mWindowAndroid.destroy(); + mWindowAndroid = null; + } } }
diff --git a/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java b/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java index 2a73263ee..8b1f24e4 100644 --- a/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java +++ b/weblayer/browser/java/org/chromium/weblayer_private/NewTabCallbackProxy.java
@@ -9,6 +9,7 @@ import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeMethods; +import org.chromium.weblayer_private.interfaces.NewTabType; /** * Owns the c++ NewTabCallback class, which is responsible for forwarding all @@ -30,8 +31,24 @@ mNativeNewTabCallbackProxy = 0; } + @NewTabType + private static int implTypeToJavaType(@ImplNewTabType int type) { + switch (type) { + case ImplNewTabType.FOREGROUND: + return NewTabType.FOREGROUND_TAB; + case ImplNewTabType.BACKGROUND: + return NewTabType.BACKGROUND_TAB; + case ImplNewTabType.NEW_POPUP: + return NewTabType.NEW_POPUP; + case ImplNewTabType.NEW_WINDOW: + return NewTabType.NEW_WINDOW; + } + assert false; + return NewTabType.FOREGROUND_TAB; + } + @CalledByNative - public void onNewTab(long nativeTab, int mode) throws RemoteException { + public void onNewTab(long nativeTab, @ImplNewTabType int mode) throws RemoteException { // This class should only be created while the tab is attached to a fragment. assert mTab.getBrowser() != null; TabImpl tab =
diff --git a/weblayer/browser/ssl_browsertest.cc b/weblayer/browser/ssl_browsertest.cc index b75c30a..1550290 100644 --- a/weblayer/browser/ssl_browsertest.cc +++ b/weblayer/browser/ssl_browsertest.cc
@@ -5,57 +5,106 @@ #include "weblayer/test/weblayer_browser_test.h" #include "base/files/file_path.h" +#include "base/macros.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "weblayer/shell/browser/shell.h" #include "weblayer/test/interstitial_utils.h" +#include "weblayer/test/test_navigation_observer.h" #include "weblayer/test/weblayer_browser_test_utils.h" namespace weblayer { -IN_PROC_BROWSER_TEST_F(WebLayerBrowserTest, SSLErrorMismatchedCertificate) { - net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS); - https_server.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); +class SSLBrowserTest : public WebLayerBrowserTest { + public: + SSLBrowserTest() = default; + ~SSLBrowserTest() override = default; - net::EmbeddedTestServer https_server_mismatched( - net::EmbeddedTestServer::TYPE_HTTPS); - https_server_mismatched.SetSSLConfig( - net::EmbeddedTestServer::CERT_MISMATCHED_NAME); - https_server_mismatched.AddDefaultHandlers( - base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); + // WebLayerBrowserTest: + void PreRunTestOnMainThread() override { + WebLayerBrowserTest::PreRunTestOnMainThread(); - ASSERT_TRUE(https_server.Start()); - ASSERT_TRUE(https_server_mismatched.Start()); + https_server_ = std::make_unique<net::EmbeddedTestServer>( + net::EmbeddedTestServer::TYPE_HTTPS); + https_server_->AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); - // First navigate to an OK page. - GURL initial_url = https_server.GetURL("/simple_page.html"); - ASSERT_EQ("127.0.0.1", initial_url.host()); + https_server_mismatched_ = std::make_unique<net::EmbeddedTestServer>( + net::EmbeddedTestServer::TYPE_HTTPS); + https_server_mismatched_->SetSSLConfig( + net::EmbeddedTestServer::CERT_MISMATCHED_NAME); + https_server_mismatched_->AddDefaultHandlers( + base::FilePath(FILE_PATH_LITERAL("weblayer/test/data"))); - NavigateAndWaitForCompletion(initial_url, shell()); - EXPECT_FALSE(IsShowingSecurityInterstitial(shell()->tab())); + ASSERT_TRUE(https_server_->Start()); + ASSERT_TRUE(https_server_mismatched_->Start()); + } - // Now do a navigation that should result in an SSL error. - GURL url_with_mismatched_cert = - https_server_mismatched.GetURL("/simple_page.html"); + void PostRunTestOnMainThread() override { + https_server_.reset(); + https_server_mismatched_.reset(); + WebLayerBrowserTest::PostRunTestOnMainThread(); + } - NavigateAndWaitForFailure(url_with_mismatched_cert, shell()); + void NavigateToOkPage() { + ASSERT_EQ("127.0.0.1", ok_url().host()); + NavigateAndWaitForCompletion(ok_url(), shell()); + EXPECT_FALSE(IsShowingSecurityInterstitial(shell()->tab())); + } - // First check that there *is* an interstitial. - EXPECT_TRUE(IsShowingSecurityInterstitial(shell()->tab())); + void NavigateToPageWithSslError() { + // Now do a navigation that should result in an SSL error. + GURL url_with_mismatched_cert = + https_server_mismatched_->GetURL("/simple_page.html"); - // Now verify that the interstitial is in fact an SSL interstitial. - EXPECT_TRUE(IsShowingSSLInterstitial(shell()->tab())); + NavigateAndWaitForFailure(url_with_mismatched_cert, shell()); - // TODO(blundell): Check the security state once security state is available - // via the public WebLayer API, following the example of //chrome's - // ssl_browsertest.cc's CheckAuthenticationBrokenState() function. + // First check that there *is* an interstitial. + ASSERT_TRUE(IsShowingSecurityInterstitial(shell()->tab())); - // TODO(blundell): Bring up test of the "Take me back" functionality - // following the example of //chrome's ssl_browsertest.cc:1467, once that - // functionality is implemented in weblayer. + // Now verify that the interstitial is in fact an SSL interstitial. + EXPECT_TRUE(IsShowingSSLInterstitial(shell()->tab())); + + // TODO(blundell): Check the security state once security state is available + // via the public WebLayer API, following the example of //chrome's + // ssl_browsertest.cc's CheckAuthenticationBrokenState() function. + } + + GURL ok_url() { return https_server_->GetURL("/simple_page.html"); } + + protected: + std::unique_ptr<net::EmbeddedTestServer> https_server_; + std::unique_ptr<net::EmbeddedTestServer> https_server_mismatched_; + + private: + DISALLOW_COPY_AND_ASSIGN(SSLBrowserTest); +}; + +// Tests clicking "take me back" on the interstitial page. +IN_PROC_BROWSER_TEST_F(SSLBrowserTest, TakeMeBack) { + NavigateToOkPage(); + NavigateToPageWithSslError(); + + // Click "Take me back". + TestNavigationObserver navigation_observer( + ok_url(), TestNavigationObserver::NavigationEvent::Completion, shell()); + ExecuteScript(shell(), "window.certificateErrorPageController.dontProceed();", + false /*use_separate_isolate*/); + navigation_observer.Wait(); + EXPECT_FALSE(IsShowingSSLInterstitial(shell()->tab())); // Check that it's possible to navigate to a new page. - NavigateAndWaitForCompletion(initial_url, shell()); + NavigateAndWaitForCompletion(https_server_->GetURL("/simple_page2.html"), + shell()); + EXPECT_FALSE(IsShowingSecurityInterstitial(shell()->tab())); +} + +// Tests navigating away from the interstitial page. +IN_PROC_BROWSER_TEST_F(SSLBrowserTest, NavigateAway) { + NavigateToOkPage(); + NavigateToPageWithSslError(); + + NavigateAndWaitForCompletion(https_server_->GetURL("/simple_page2.html"), + shell()); EXPECT_FALSE(IsShowingSecurityInterstitial(shell()->tab())); }
diff --git a/weblayer/public/javatests/BUILD.gn b/weblayer/public/javatests/BUILD.gn new file mode 100644 index 0000000..9369d79 --- /dev/null +++ b/weblayer/public/javatests/BUILD.gn
@@ -0,0 +1,16 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/android/config.gni") +import("//build/config/android/rules.gni") + +android_library("weblayer_public_javatests") { + testonly = true + java_files = [ "org/chromium/weblayer/ObserverListTest.java" ] + deps = [ + "//base:base_java_test_support", + "//third_party/junit:junit", + "//weblayer/public/java", + ] +}
diff --git a/weblayer/public/javatests/org/chromium/weblayer/ObserverListTest.java b/weblayer/public/javatests/org/chromium/weblayer/ObserverListTest.java new file mode 100644 index 0000000..3534381 --- /dev/null +++ b/weblayer/public/javatests/org/chromium/weblayer/ObserverListTest.java
@@ -0,0 +1,332 @@ +// 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.weblayer; + +import android.support.test.filters.SmallTest; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.base.test.BaseJUnit4ClassRunner; + +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Tests for (@link ObserverList}. + */ +@RunWith(BaseJUnit4ClassRunner.class) +public class ObserverListTest { + interface Observer { + void observe(int x); + } + + private static class Foo implements Observer { + private final int mScalar; + private int mTotal; + + Foo(int scalar) { + mScalar = scalar; + } + + @Override + public void observe(int x) { + mTotal += x * mScalar; + } + } + + /** + * An observer which add a given Observer object to the list when observe is called. + */ + private static class FooAdder implements Observer { + private final ObserverList<Observer> mList; + private final Observer mLucky; + + FooAdder(ObserverList<Observer> list, Observer oblivious) { + mList = list; + mLucky = oblivious; + } + + @Override + public void observe(int x) { + mList.addObserver(mLucky); + } + } + + /** + * An observer which removes a given Observer object from the list when observe is called. + */ + private static class FooRemover implements Observer { + private final ObserverList<Observer> mList; + private final Observer mDoomed; + + FooRemover(ObserverList<Observer> list, Observer innocent) { + mList = list; + mDoomed = innocent; + } + + @Override + public void observe(int x) { + mList.removeObserver(mDoomed); + } + } + + private static <T> int getSizeOfIterable(Iterable<T> iterable) { + if (iterable instanceof Collection<?>) return ((Collection<?>) iterable).size(); + int num = 0; + for (T el : iterable) num++; + return num; + } + + @Test + @SmallTest + public void testRemoveWhileIteration() { + ObserverList<Observer> observerList = new ObserverList<Observer>(); + Foo a = new Foo(1); + Foo b = new Foo(-1); + Foo c = new Foo(1); + Foo d = new Foo(-1); + Foo e = new Foo(-1); + FooRemover evil = new FooRemover(observerList, c); + + observerList.addObserver(a); + observerList.addObserver(b); + + for (Observer obs : observerList) obs.observe(10); + + // Removing an observer not in the list should do nothing. + observerList.removeObserver(e); + + observerList.addObserver(evil); + observerList.addObserver(c); + observerList.addObserver(d); + + for (Observer obs : observerList) obs.observe(10); + + // observe should be called twice on a. + Assert.assertEquals(20, a.mTotal); + // observe should be called twice on b. + Assert.assertEquals(-20, b.mTotal); + // evil removed c from the observerList before it got any callbacks. + Assert.assertEquals(0, c.mTotal); + // observe should be called once on d. + Assert.assertEquals(-10, d.mTotal); + // e was never added to the list, observe should not be called. + Assert.assertEquals(0, e.mTotal); + } + + @Test + @SmallTest + public void testAddWhileIteration() { + ObserverList<Observer> observerList = new ObserverList<Observer>(); + Foo a = new Foo(1); + Foo b = new Foo(-1); + Foo c = new Foo(1); + FooAdder evil = new FooAdder(observerList, c); + + observerList.addObserver(evil); + observerList.addObserver(a); + observerList.addObserver(b); + + for (Observer obs : observerList) obs.observe(10); + + Assert.assertTrue(observerList.hasObserver(c)); + Assert.assertEquals(10, a.mTotal); + Assert.assertEquals(-10, b.mTotal); + Assert.assertEquals(0, c.mTotal); + } + + @Test + @SmallTest + public void testIterator() { + ObserverList<Integer> observerList = new ObserverList<Integer>(); + observerList.addObserver(5); + observerList.addObserver(10); + observerList.addObserver(15); + Assert.assertEquals(3, getSizeOfIterable(observerList)); + + observerList.removeObserver(10); + Assert.assertEquals(2, getSizeOfIterable(observerList)); + + Iterator<Integer> it = observerList.iterator(); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(5 == it.next()); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(15 == it.next()); + Assert.assertFalse(it.hasNext()); + + boolean removeExceptionThrown = false; + try { + it.remove(); + Assert.fail("Expecting UnsupportedOperationException to be thrown here."); + } catch (UnsupportedOperationException e) { + removeExceptionThrown = true; + } + Assert.assertTrue(removeExceptionThrown); + Assert.assertEquals(2, getSizeOfIterable(observerList)); + + boolean noElementExceptionThrown = false; + try { + it.next(); + Assert.fail("Expecting NoSuchElementException to be thrown here."); + } catch (NoSuchElementException e) { + noElementExceptionThrown = true; + } + Assert.assertTrue(noElementExceptionThrown); + } + + @Test + @SmallTest + public void testRewindableIterator() { + ObserverList<Integer> observerList = new ObserverList<Integer>(); + observerList.addObserver(5); + observerList.addObserver(10); + observerList.addObserver(15); + Assert.assertEquals(3, getSizeOfIterable(observerList)); + + ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator(); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(5 == it.next()); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(10 == it.next()); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(15 == it.next()); + Assert.assertFalse(it.hasNext()); + + it.rewind(); + + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(5 == it.next()); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(10 == it.next()); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(15 == it.next()); + Assert.assertEquals(5, (int) observerList.mObservers.get(0)); + observerList.removeObserver(5); + Assert.assertEquals(null, observerList.mObservers.get(0)); + + it.rewind(); + + Assert.assertEquals(10, (int) observerList.mObservers.get(0)); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(10 == it.next()); + Assert.assertTrue(it.hasNext()); + Assert.assertTrue(15 == it.next()); + } + + @Test + @SmallTest + public void testAddObserverReturnValue() { + ObserverList<Object> observerList = new ObserverList<Object>(); + + Object a = new Object(); + Assert.assertTrue(observerList.addObserver(a)); + Assert.assertFalse(observerList.addObserver(a)); + + Object b = new Object(); + Assert.assertTrue(observerList.addObserver(b)); + Assert.assertFalse(observerList.addObserver(null)); + } + + @Test + @SmallTest + public void testRemoveObserverReturnValue() { + ObserverList<Object> observerList = new ObserverList<Object>(); + + Object a = new Object(); + Object b = new Object(); + observerList.addObserver(a); + observerList.addObserver(b); + + Assert.assertTrue(observerList.removeObserver(a)); + Assert.assertFalse(observerList.removeObserver(a)); + Assert.assertFalse(observerList.removeObserver(new Object())); + Assert.assertTrue(observerList.removeObserver(b)); + Assert.assertFalse(observerList.removeObserver(null)); + + // If we remove an object while iterating, it will be replaced by 'null'. + observerList.addObserver(a); + Assert.assertTrue(observerList.removeObserver(a)); + Assert.assertFalse(observerList.removeObserver(null)); + } + + @Test + @SmallTest + public void testSize() { + ObserverList<Object> observerList = new ObserverList<Object>(); + + Assert.assertEquals(0, observerList.size()); + Assert.assertTrue(observerList.isEmpty()); + + observerList.addObserver(null); + Assert.assertEquals(0, observerList.size()); + Assert.assertTrue(observerList.isEmpty()); + + Object a = new Object(); + observerList.addObserver(a); + Assert.assertEquals(1, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.addObserver(a); + Assert.assertEquals(1, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.addObserver(null); + Assert.assertEquals(1, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + Object b = new Object(); + observerList.addObserver(b); + Assert.assertEquals(2, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.removeObserver(null); + Assert.assertEquals(2, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.removeObserver(new Object()); + Assert.assertEquals(2, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.removeObserver(b); + Assert.assertEquals(1, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.removeObserver(b); + Assert.assertEquals(1, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.removeObserver(a); + Assert.assertEquals(0, observerList.size()); + Assert.assertTrue(observerList.isEmpty()); + + observerList.removeObserver(a); + observerList.removeObserver(b); + observerList.removeObserver(null); + observerList.removeObserver(new Object()); + Assert.assertEquals(0, observerList.size()); + Assert.assertTrue(observerList.isEmpty()); + + observerList.addObserver(new Object()); + observerList.addObserver(new Object()); + observerList.addObserver(new Object()); + observerList.addObserver(a); + Assert.assertEquals(4, observerList.size()); + Assert.assertFalse(observerList.isEmpty()); + + observerList.clear(); + Assert.assertEquals(0, observerList.size()); + Assert.assertTrue(observerList.isEmpty()); + + observerList.removeObserver(a); + observerList.removeObserver(b); + observerList.removeObserver(null); + observerList.removeObserver(new Object()); + Assert.assertEquals(0, observerList.size()); + Assert.assertTrue(observerList.isEmpty()); + } +}
diff --git a/weblayer/shell/android/BUILD.gn b/weblayer/shell/android/BUILD.gn index be8f8e5..7028929 100644 --- a/weblayer/shell/android/BUILD.gn +++ b/weblayer/shell/android/BUILD.gn
@@ -192,6 +192,7 @@ "//content/public/test/android:content_java_test_support", "//net/android:net_java_test_support", "//third_party/android_support_test_runner:runner_java", + "//weblayer/public/javatests:weblayer_public_javatests", ] java_files = [ "javatests/src/org/chromium/weblayer/test/DataClearingTest.java",
diff --git a/weblayer/test/BUILD.gn b/weblayer/test/BUILD.gn index 262ab3c..db48205 100644 --- a/weblayer/test/BUILD.gn +++ b/weblayer/test/BUILD.gn
@@ -94,6 +94,8 @@ "interstitial_utils.h", "test_launcher_delegate_impl.cc", "test_launcher_delegate_impl.h", + "test_navigation_observer.cc", + "test_navigation_observer.h", "weblayer_browser_test.cc", "weblayer_browser_test.h", "weblayer_browser_test_test.cc",
diff --git a/weblayer/test/test_navigation_observer.cc b/weblayer/test/test_navigation_observer.cc new file mode 100644 index 0000000..00de95c5 --- /dev/null +++ b/weblayer/test/test_navigation_observer.cc
@@ -0,0 +1,54 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "weblayer/test/test_navigation_observer.h" + +#include "base/test/bind_test_util.h" +#include "url/gurl.h" +#include "weblayer/public/navigation.h" +#include "weblayer/public/navigation_controller.h" +#include "weblayer/public/tab.h" +#include "weblayer/shell/browser/shell.h" + +namespace weblayer { + +TestNavigationObserver::TestNavigationObserver(const GURL& url, + NavigationEvent target_event, + Shell* shell) + : url_(url), target_event_(target_event), tab_(shell->tab()) { + tab_->GetNavigationController()->AddObserver(this); +} + +TestNavigationObserver::~TestNavigationObserver() { + tab_->GetNavigationController()->RemoveObserver(this); +} + +void TestNavigationObserver::NavigationCompleted(Navigation* navigation) { + if (navigation->GetURL() == url_) + observed_event_ = NavigationEvent::Completion; + CheckNavigationCompleted(); +} + +void TestNavigationObserver::NavigationFailed(Navigation* navigation) { + if (navigation->GetURL() == url_) + observed_event_ = NavigationEvent::Failure; + CheckNavigationCompleted(); +} + +void TestNavigationObserver::LoadStateChanged(bool is_loading, + bool to_different_document) { + done_loading_ = !is_loading; + CheckNavigationCompleted(); +} + +void TestNavigationObserver::CheckNavigationCompleted() { + if (done_loading_ && observed_event_ == target_event_) + run_loop_.Quit(); +} + +void TestNavigationObserver::Wait() { + run_loop_.Run(); +} + +} // namespace weblayer
diff --git a/weblayer/test/test_navigation_observer.h b/weblayer/test/test_navigation_observer.h new file mode 100644 index 0000000..fbfddee8 --- /dev/null +++ b/weblayer/test/test_navigation_observer.h
@@ -0,0 +1,54 @@ +// 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. + +#ifndef WEBLAYER_TEST_TEST_NAVIGATION_OBSERVER_H_ +#define WEBLAYER_TEST_TEST_NAVIGATION_OBSERVER_H_ + +#include "base/macros.h" +#include "base/optional.h" +#include "base/run_loop.h" +#include "url/gurl.h" +#include "weblayer/public/navigation_observer.h" + +namespace weblayer { + +class Shell; +class Tab; + +// A helper that waits for a navigation to finish. +class TestNavigationObserver : public NavigationObserver { + public: + enum class NavigationEvent { Completion, Failure }; + + // Creates an instance that begins waiting for a Navigation within |shell| and + // to |url| to either complete or fail as per |target_event|. + TestNavigationObserver(const GURL& url, + NavigationEvent target_event, + Shell* shell); + ~TestNavigationObserver() override; + + // Spins a RunLoop until the requested type of navigation event is observed. + void Wait(); + + private: + // NavigationObserver implementation: + void NavigationCompleted(Navigation* navigation) override; + void NavigationFailed(Navigation* navigation) override; + void LoadStateChanged(bool is_loading, bool to_different_document) override; + + void CheckNavigationCompleted(); + + const GURL url_; + base::Optional<NavigationEvent> observed_event_; + NavigationEvent target_event_; + Tab* tab_; + bool done_loading_ = false; + base::RunLoop run_loop_; + + DISALLOW_COPY_AND_ASSIGN(TestNavigationObserver); +}; + +} // namespace weblayer + +#endif // WEBLAYER_TEST_TEST_NAVIGATION_OBSERVER_H_
diff --git a/weblayer/test/weblayer_browser_test_utils.cc b/weblayer/test/weblayer_browser_test_utils.cc index f5891bc3..19b69f4 100644 --- a/weblayer/test/weblayer_browser_test_utils.cc +++ b/weblayer/test/weblayer_browser_test_utils.cc
@@ -4,98 +4,37 @@ #include "weblayer/test/weblayer_browser_test_utils.h" -#include "base/run_loop.h" #include "base/strings/utf_string_conversions.h" #include "base/test/bind_test_util.h" #include "url/gurl.h" -#include "weblayer/public/navigation.h" #include "weblayer/public/navigation_controller.h" -#include "weblayer/public/navigation_observer.h" #include "weblayer/public/tab.h" #include "weblayer/shell/browser/shell.h" +#include "weblayer/test/test_navigation_observer.h" namespace weblayer { namespace { -// Runs |closure| once |url| is successfully navigated to. -class TestNavigationObserver : public NavigationObserver { - public: - enum class NavigationEventToObserve { Completion, Failure }; - - TestNavigationObserver(base::OnceClosure closure, - const GURL& url, - NavigationEventToObserve event, - Shell* shell) - : closure_(std::move(closure)), - url_(url), - event_(event), - tab_(shell->tab()) { - tab_->GetNavigationController()->AddObserver(this); - } - - ~TestNavigationObserver() override { - tab_->GetNavigationController()->RemoveObserver(this); - } - - private: - // NavigationObserver implementation: - void NavigationCompleted(Navigation* navigation) override { - if (navigation->GetURL() == url_ && - event_ == NavigationEventToObserve::Completion) { - navigation_complete_ = true; - CheckComplete(); - } - } - - void NavigationFailed(Navigation* navigation) override { - if (navigation->GetURL() == url_ && - event_ == NavigationEventToObserve::Failure) { - std::move(closure_).Run(); - } - } - - void LoadStateChanged(bool is_loading, bool to_different_document) override { - done_loading_ = !is_loading; - CheckComplete(); - } - - void CheckComplete() { - if (done_loading_ && navigation_complete_) - std::move(closure_).Run(); - } - - base::OnceClosure closure_; - const GURL url_; - NavigationEventToObserve event_; - Tab* tab_; - bool done_loading_ = false; - bool navigation_complete_ = false; -}; - // Navigates to |url| in |shell| and waits for |event| to occur. -void NavigateAndWaitForEvent( - const GURL& url, - Shell* shell, - TestNavigationObserver::NavigationEventToObserve event) { - base::RunLoop run_loop; - TestNavigationObserver test_observer(run_loop.QuitClosure(), url, event, - shell); - +void NavigateAndWaitForEvent(const GURL& url, + Shell* shell, + TestNavigationObserver::NavigationEvent event) { + TestNavigationObserver test_observer(url, event, shell); shell->tab()->GetNavigationController()->Navigate(url); - run_loop.Run(); + test_observer.Wait(); } } // namespace void NavigateAndWaitForCompletion(const GURL& url, Shell* shell) { - NavigateAndWaitForEvent( - url, shell, TestNavigationObserver::NavigationEventToObserve::Completion); + NavigateAndWaitForEvent(url, shell, + TestNavigationObserver::NavigationEvent::Completion); } void NavigateAndWaitForFailure(const GURL& url, Shell* shell) { - NavigateAndWaitForEvent( - url, shell, TestNavigationObserver::NavigationEventToObserve::Failure); + NavigateAndWaitForEvent(url, shell, + TestNavigationObserver::NavigationEvent::Failure); } base::Value ExecuteScript(Shell* shell,