diff --git a/DEPS b/DEPS index b156b87..f73e6a18 100644 --- a/DEPS +++ b/DEPS
@@ -145,11 +145,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': 'f75996469d02b1bfba8b246c526a6d06233ced44', + 'skia_revision': 'e7c1b99e635b49fc7a796fba59d356294aaf0b8f', # 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': '4b08436ce71ecb074e9fb7493567cfbb04ccafb0', + 'v8_revision': '17d26c04a4afdd92392b5f1b208057ad16474b7a', # 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. @@ -157,15 +157,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'b3eeb2a403548bc44fc605c051b622081de42410', + 'angle_revision': '99cffe5db4197d5e780ba21238874e983b380e88', # 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': '5e4e8b0af5fa0b00de29c77ecf56014e409b53c0', + 'swiftshader_revision': '30ee92ec516340b59d88d62db778b3d9071816d5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'f2095928371177683ee4e1a746f43633a43c303e', + 'pdfium_revision': '60044886a39365bbf10be7f8894a71dcd3275794', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling BoringSSL # and whatever else without interference from each other. @@ -208,7 +208,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': '942e493326d11faffa51617ad07a82831f9408fe', + 'catapult_revision': '73af388b695c1ed27f88df14f9df1d2f6761d4be', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -280,7 +280,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': '2fb628da46f1af9c0155e08c36d00ac63612c569', + 'dawn_revision': '40618d0b93aa46edc2906ef318d50fb1cf4fe80a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -814,7 +814,7 @@ # Build tools for Chrome OS. Note: This depends on third_party/pyelftools. 'src/third_party/chromite': { - 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '14ef7d57c13dd54b9403eb4be300ab4cf5e5cac5', + 'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'd6195b651b192e6de7aecfefa75cd6a1adc7a524', 'condition': 'checkout_linux', }, @@ -1184,7 +1184,7 @@ Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '6f26bce0b1c4e8ce0e13332f7c0083788def5fdf', 'src/third_party/openscreen/src': - Var('chromium_git') + '/openscreen' + '@' + '5c4739296aaa68a75dd7b06b6441f4abdc24360c', + Var('chromium_git') + '/openscreen' + '@' + '063c3b57139678d82dc0ae8c9d18b10bdeb94220', 'src/third_party/openxr/src': { 'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + 'c52d3b40dd802353c1f2ceec139922b374c1373a', @@ -1212,7 +1212,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '565082dac7842caf6aed931243439d5cdf679265', + Var('android_git') + '/platform/external/perfetto.git' + '@' + '34aac4b486cd3038592e94efaf088d835d85a774', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3', @@ -1421,7 +1421,7 @@ Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'), 'src-internal': { - 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@283aa6a07c39b0faf937b73d23376510c2afc487', + 'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@e43bce26f435feacdcbf8862333aeeb2bd69e6ae', 'condition': 'checkout_src_internal', },
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn index a9a8d74..367412e 100644 --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn
@@ -880,6 +880,7 @@ "java/src/org/chromium/android_webview/ui/util/CrashInfoLoader.java", "java/src/org/chromium/android_webview/ui/util/UnuploadedFilesStateLoader.java", "java/src/org/chromium/android_webview/ui/util/UploadedCrashesInfoLoader.java", + "java/src/org/chromium/android_webview/ui/util/WebViewCrashInfoCollector.java", "java/src/org/chromium/android_webview/ui/util/WebViewCrashLogParser.java", ] deps = [
diff --git a/android_webview/browser/aw_pdf_exporter.cc b/android_webview/browser/aw_pdf_exporter.cc index 886d358..5e0427d 100644 --- a/android_webview/browser/aw_pdf_exporter.cc +++ b/android_webview/browser/aw_pdf_exporter.cc
@@ -68,7 +68,7 @@ JNI_AwPdfExporter_GetPageRanges(env, pages, &page_ranges); AwPrintManager* print_manager = AwPrintManager::CreateForWebContents( web_contents_, CreatePdfSettings(env, obj, page_ranges), fd, - base::Bind(&AwPdfExporter::DidExportPdf, base::Unretained(this))); + base::BindOnce(&AwPdfExporter::DidExportPdf, base::Unretained(this))); if (!print_manager->PrintNow()) DidExportPdf(0);
diff --git a/android_webview/browser/aw_print_manager.cc b/android_webview/browser/aw_print_manager.cc index 5c9d4dc..9cb41ca 100644 --- a/android_webview/browser/aw_print_manager.cc +++ b/android_webview/browser/aw_print_manager.cc
@@ -64,7 +64,7 @@ void AwPrintManager::PdfWritingDone(int page_count) { if (pdf_writing_done_callback_) - pdf_writing_done_callback_.Run(page_count); + std::move(pdf_writing_done_callback_).Run(page_count); // Invalidate the file descriptor so it doesn't get reused. fd_ = -1; } @@ -123,13 +123,14 @@ return; } + DCHECK(pdf_writing_done_callback_); base::PostTaskAndReplyWithResult( base::CreateTaskRunner({base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}) .get(), - FROM_HERE, base::BindRepeating(&SaveDataToFd, fd_, number_pages_, data), - pdf_writing_done_callback_); + FROM_HERE, base::BindOnce(&SaveDataToFd, fd_, number_pages_, data), + std::move(pdf_writing_done_callback_)); } WEB_CONTENTS_USER_DATA_KEY_IMPL(AwPrintManager)
diff --git a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc index c38ba61..ec45d576 100644 --- a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc +++ b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc
@@ -66,13 +66,15 @@ void AwProxyingRestrictedCookieManager::GetAllForUrl( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, network::mojom::CookieManagerGetOptionsPtr options, GetAllForUrlCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (AllowCookies(url, site_for_cookies)) { underlying_restricted_cookie_manager_->GetAllForUrl( - url, site_for_cookies, std::move(options), std::move(callback)); + url, site_for_cookies, top_frame_origin, std::move(options), + std::move(callback)); } else { std::move(callback).Run(std::vector<net::CanonicalCookie>()); } @@ -82,12 +84,13 @@ const net::CanonicalCookie& cookie, const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, SetCanonicalCookieCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (AllowCookies(url, site_for_cookies)) { underlying_restricted_cookie_manager_->SetCanonicalCookie( - cookie, url, site_for_cookies, std::move(callback)); + cookie, url, site_for_cookies, top_frame_origin, std::move(callback)); } else { std::move(callback).Run(false); } @@ -96,6 +99,7 @@ void AwProxyingRestrictedCookieManager::AddChangeListener( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, network::mojom::CookieChangeListenerPtr listener, AddChangeListenerCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); @@ -110,20 +114,21 @@ mojo::MakeRequest(&proxy_listener_ptr)); underlying_restricted_cookie_manager_->AddChangeListener( - url, site_for_cookies, std::move(proxy_listener_ptr), + url, site_for_cookies, top_frame_origin, std::move(proxy_listener_ptr), std::move(callback)); } void AwProxyingRestrictedCookieManager::SetCookieFromString( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const std::string& cookie, SetCookieFromStringCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (AllowCookies(url, site_for_cookies)) { underlying_restricted_cookie_manager_->SetCookieFromString( - url, site_for_cookies, cookie, std::move(callback)); + url, site_for_cookies, top_frame_origin, cookie, std::move(callback)); } else { std::move(callback).Run(); } @@ -132,12 +137,13 @@ void AwProxyingRestrictedCookieManager::GetCookiesString( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, GetCookiesStringCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (AllowCookies(url, site_for_cookies)) { underlying_restricted_cookie_manager_->GetCookiesString( - url, site_for_cookies, std::move(callback)); + url, site_for_cookies, top_frame_origin, std::move(callback)); } else { std::move(callback).Run(""); } @@ -146,6 +152,7 @@ void AwProxyingRestrictedCookieManager::CookiesEnabledFor( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, CookiesEnabledForCallback callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); std::move(callback).Run(AllowCookies(url, site_for_cookies));
diff --git a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h index cd7bcb39..3c052349 100644 --- a/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h +++ b/android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.h
@@ -35,28 +35,34 @@ // network::mojom::RestrictedCookieManager interface: void GetAllForUrl(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, network::mojom::CookieManagerGetOptionsPtr options, GetAllForUrlCallback callback) override; void SetCanonicalCookie(const net::CanonicalCookie& cookie, const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, SetCanonicalCookieCallback callback) override; void AddChangeListener(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, network::mojom::CookieChangeListenerPtr listener, AddChangeListenerCallback callback) override; void SetCookieFromString(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const std::string& cookie, SetCookieFromStringCallback callback) override; void GetCookiesString(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, GetCookiesStringCallback callback) override; void CookiesEnabledFor(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, CookiesEnabledForCallback callback) override; // This one is internal.
diff --git a/android_webview/java/src/org/chromium/android_webview/ui/util/WebViewCrashInfoCollector.java b/android_webview/java/src/org/chromium/android_webview/ui/util/WebViewCrashInfoCollector.java new file mode 100644 index 0000000..a8da490 --- /dev/null +++ b/android_webview/java/src/org/chromium/android_webview/ui/util/WebViewCrashInfoCollector.java
@@ -0,0 +1,124 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +package org.chromium.android_webview.ui.util; + +import org.chromium.android_webview.common.crash.CrashInfo; +import org.chromium.android_webview.common.crash.CrashInfo.UploadState; +import org.chromium.android_webview.services.CrashReceiverService; +import org.chromium.base.VisibleForTesting; +import org.chromium.components.minidump_uploader.CrashFileManager; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Aggregates webview crash info from different sources into one single list. + * This list may be used to be displayed in a Crash UI. + */ +public class WebViewCrashInfoCollector { + private final CrashInfoLoader[] mCrashInfoLoaders; + + public WebViewCrashInfoCollector() { + CrashFileManager crashFileManager = + new CrashFileManager(CrashReceiverService.getOrCreateWebViewCrashDir()); + + mCrashInfoLoaders = new CrashInfoLoader[] { + new UploadedCrashesInfoLoader(crashFileManager.getCrashUploadLogFile()), + new UnuploadedFilesStateLoader(crashFileManager), + + new WebViewCrashLogParser(CrashReceiverService.getWebViewCrashLogDir())}; + } + + /** + * Aggregates crashes from different resources and removes duplicates. + * Crashes are sorted by most recent (crash capture time). + * + * @param limit the max size of crashes to be returned, if negative to return all crashes. + * @return list of size {@code limit} or less, sorted by the most recent. + */ + public List<CrashInfo> loadCrashesInfo(int limit) { + List<CrashInfo> allCrashes = new ArrayList<>(); + for (CrashInfoLoader loader : mCrashInfoLoaders) { + allCrashes.addAll(loader.loadCrashesInfo()); + } + allCrashes = mergeDuplicates(allCrashes); + sortByMostRecent(allCrashes); + + if (limit < 0 || limit >= allCrashes.size()) return allCrashes; + return allCrashes.subList(0, limit); + } + + /** + * Merge duplicate crashes (crashes which have the same local-id) into one object. + */ + @VisibleForTesting + public static List<CrashInfo> mergeDuplicates(List<CrashInfo> crashesList) { + Map<String, CrashInfo> crashInfoMap = new HashMap<>(); + for (CrashInfo c : crashesList) { + CrashInfo previous = crashInfoMap.get(c.localId); + if (previous != null) { + mergeCrashInfo(previous, c); + } else { + crashInfoMap.put(c.localId, c); + } + } + return new ArrayList<CrashInfo>(crashInfoMap.values()); + } + + /** + * Sort the list by most recent capture time, if capture time is equal or is unknown (-1), + * upload time will be used. + */ + @VisibleForTesting + public static void sortByMostRecent(List<CrashInfo> list) { + Collections.sort(list, (a, b) -> { + if (a.captureTime != b.captureTime) return a.captureTime < b.captureTime ? 1 : -1; + if (a.uploadTime != b.uploadTime) return a.uploadTime < b.uploadTime ? 1 : -1; + return 0; + }); + } + + private static <T> T getFirstNonNull(T a, T b) { + return a != null ? a : b; + } + + /** + * Merge values from the second object into the first object if the value in the first object is + * {@code null}. + */ + @VisibleForTesting + public static void mergeCrashInfo(CrashInfo a, CrashInfo b) { + // localId is not merged since it's two CrashInfo objects should be only merged if they have + // the same localId. + a.captureTime = a.captureTime != -1 ? a.captureTime : b.captureTime; + a.uploadId = getFirstNonNull(a.uploadId, b.uploadId); + a.uploadTime = a.uploadTime != -1 ? a.uploadTime : b.uploadTime; + a.packageName = getFirstNonNull(a.packageName, b.packageName); + a.variations = getFirstNonNull(a.variations, b.variations); + + // When merging two CrashInfos if one of the two UploadStates is UPLOADED then the merged + // object will have an UPLOADED state regardless of the order. Difference in UploadState my + // be caused by the file suffix not updated or deleted by the time + // UnuploadedFilesStateLoader parses the crash directory. + if (a.uploadState != null && b.uploadState != null) { + if (a.uploadState == UploadState.UPLOADED || b.uploadState == UploadState.UPLOADED) { + a.uploadState = UploadState.UPLOADED; + } else { + assert a.uploadState == b.uploadState; + } + } else { + a.uploadState = getFirstNonNull(a.uploadState, b.uploadState); + } + // Since capture time may be the last time the crash file is modified, the oldest capture + // time will be used regardless of the merging order. + if (a.captureTime != -1 && b.captureTime != -1) { + a.captureTime = Math.min(a.captureTime, b.captureTime); + } else { + a.captureTime = a.captureTime != -1 ? a.captureTime : b.captureTime; + } + } +}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashInfoCollectorTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashInfoCollectorTest.java new file mode 100644 index 0000000..ffca334 --- /dev/null +++ b/android_webview/javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashInfoCollectorTest.java
@@ -0,0 +1,185 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.android_webview.test.ui.util; + +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; + +import static org.chromium.android_webview.test.OnlyRunIn.ProcessMode.SINGLE_PROCESS; + +import android.support.test.filters.SmallTest; + +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.chromium.android_webview.common.crash.CrashInfo; +import org.chromium.android_webview.common.crash.CrashInfo.UploadState; +import org.chromium.android_webview.test.AwJUnit4ClassRunner; +import org.chromium.android_webview.test.OnlyRunIn; +import org.chromium.android_webview.ui.util.WebViewCrashInfoCollector; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +/** + * Unit tests for WebViewCrashInfoCollector. + */ +@RunWith(AwJUnit4ClassRunner.class) +@OnlyRunIn(SINGLE_PROCESS) +public class WebViewCrashInfoCollectorTest { + private CrashInfo createCrashInfo(String localId, long captureTime, String uploadId, + long uploadTime, String packageName, String variations, UploadState state) { + CrashInfo crashInfo = new CrashInfo(localId); + crashInfo.captureTime = captureTime; + crashInfo.uploadId = uploadId; + crashInfo.uploadTime = uploadTime; + crashInfo.packageName = packageName; + if (variations != null) crashInfo.variations = Arrays.asList(variations.split(",")); + crashInfo.uploadState = state; + + return crashInfo; + } + + private class CrashInfoEqualityMatcher extends BaseMatcher<CrashInfo> { + private final CrashInfo mCrashInfo; + + CrashInfoEqualityMatcher(CrashInfo crashInfo) { + mCrashInfo = crashInfo; + } + + @Override + public boolean matches(Object o) { + if (o == mCrashInfo) return true; + if (o == null || o.getClass() != mCrashInfo.getClass()) return false; + + CrashInfo c = (CrashInfo) o; + return mCrashInfo.uploadState == c.uploadState + && Objects.equals(mCrashInfo.localId, c.localId) + && mCrashInfo.captureTime == c.captureTime + && Objects.equals(mCrashInfo.packageName, c.packageName) + && Objects.equals(mCrashInfo.variations, c.variations) + && Objects.equals(mCrashInfo.uploadId, c.uploadId) + && mCrashInfo.uploadTime == c.uploadTime; + } + + @Override + public void describeTo(Description description) { + description.appendText("equals CrashInfo"); + } + } + + /** + * Test that merging two {@code CrashInfo} objects works correctly. + */ + @Test + @SmallTest + public void testMergeCrashInfo() { + CrashInfo a = createCrashInfo("123456", 10987654321L, null, -1, null, "123456,78910", null); + CrashInfo b = createCrashInfo( + "123456", -1, "abcdefg", 12345678910L, null, null, UploadState.UPLOADED); + WebViewCrashInfoCollector.mergeCrashInfo(a, b); + Assert.assertEquals("123456", a.localId); + Assert.assertEquals(10987654321L, a.captureTime); + Assert.assertEquals("abcdefg", a.uploadId); + Assert.assertEquals(12345678910L, a.uploadTime); + Assert.assertNull(a.packageName); + Assert.assertEquals(Arrays.asList("123456", "78910"), a.variations); + Assert.assertEquals(UploadState.UPLOADED, a.uploadState); + } + + /** + * Test that merging two {@code CrashInfo} objects works correctly. + */ + @Test + @SmallTest + public void testMergeCrashInfo_differentUploadStates() { + CrashInfo a = createCrashInfo("123456", -1, null, -1, null, null, UploadState.PENDING); + CrashInfo b = createCrashInfo("123456", -1, null, -1, null, null, UploadState.UPLOADED); + WebViewCrashInfoCollector.mergeCrashInfo(a, b); + Assert.assertEquals("123456", a.localId); + // UPLOADED state is the merge result, regardless of order. + Assert.assertEquals(UploadState.UPLOADED, a.uploadState); + } + + /** + * Test that merging two {@code CrashInfo} objects works correctly. + */ + @Test + @SmallTest + public void testMergeCrashInfo_differentCaptureTime() { + CrashInfo a = createCrashInfo("123456", 1234567, null, -1, null, null, null); + CrashInfo b = createCrashInfo("123456", 1234555, null, -1, null, null, null); + WebViewCrashInfoCollector.mergeCrashInfo(a, b); + Assert.assertEquals("123456", a.localId); + // Older capture time is the merging result regardless of the order. + Assert.assertEquals(1234555, a.captureTime); + } + + /** + * Test that merging {@code CrashInfo} that has the same {@code localID} works correctly. + */ + @Test + @SmallTest + public void testMergeDuplicates() { + List<CrashInfo> testList = Arrays.asList( + createCrashInfo("xyz123", 112233445566L, null, -1, null, null, UploadState.PENDING), + createCrashInfo( + "def789", -1, "55667788", 123344556677L, null, null, UploadState.UPLOADED), + createCrashInfo("abc456", -1, null, -1, null, null, UploadState.PENDING), + createCrashInfo( + "xyz123", 112233445566L, null, -1, "com.test.package", "222222", null), + createCrashInfo("abc456", 445566778899L, null, -1, "org.test.package", null, null), + createCrashInfo("abc456", -1, null, -1, null, null, null), + createCrashInfo( + "xyz123", -1, "11223344", 223344556677L, null, null, UploadState.UPLOADED)); + List<CrashInfo> uniqueList = WebViewCrashInfoCollector.mergeDuplicates(testList); + Assert.assertThat(uniqueList, + containsInAnyOrder( + new CrashInfoEqualityMatcher(createCrashInfo("abc456", 445566778899L, null, + -1, "org.test.package", null, UploadState.PENDING)), + new CrashInfoEqualityMatcher( + createCrashInfo("xyz123", 112233445566L, "11223344", 223344556677L, + "com.test.package", "222222", UploadState.UPLOADED)), + new CrashInfoEqualityMatcher(createCrashInfo("def789", -1, "55667788", + 123344556677L, null, null, UploadState.UPLOADED)))); + } + + /** + * Test that sort method works correctly; it sorts by recent crashes first (capture time then + * upload time). + */ + @Test + @SmallTest + public void testSortByRecentCaptureTime() { + List<CrashInfo> testList = Arrays.asList( + createCrashInfo("xyz123", -1, "11223344", 123L, null, null, UploadState.UPLOADED), + createCrashInfo("def789", 111L, "55667788", 100L, null, null, UploadState.UPLOADED), + createCrashInfo("abc456", -1, null, -1, null, null, UploadState.PENDING), + createCrashInfo("ghijkl", 112L, null, -1, "com.test.package", "222222", null), + createCrashInfo("abc456", 112L, null, 112L, "org.test.package", null, null), + createCrashInfo(null, 100, "11223344", -1, "com.test.package", null, null), + createCrashInfo("abc123", 100, null, -1, null, null, null)); + WebViewCrashInfoCollector.sortByMostRecent(testList); + Assert.assertThat(testList, + contains(new CrashInfoEqualityMatcher(createCrashInfo( + "abc456", 112L, null, 112L, "org.test.package", null, null)), + new CrashInfoEqualityMatcher(createCrashInfo( + "ghijkl", 112L, null, -1, "com.test.package", "222222", null)), + new CrashInfoEqualityMatcher(createCrashInfo("def789", 111L, "55667788", + 100L, null, null, UploadState.UPLOADED)), + new CrashInfoEqualityMatcher(createCrashInfo( + null, 100, "11223344", -1, "com.test.package", null, null)), + new CrashInfoEqualityMatcher( + createCrashInfo("abc123", 100, null, -1, null, null, null)), + new CrashInfoEqualityMatcher(createCrashInfo( + "xyz123", -1, "11223344", 123L, null, null, UploadState.UPLOADED)), + new CrashInfoEqualityMatcher(createCrashInfo( + "abc456", -1, null, -1, null, null, UploadState.PENDING)))); + } +}
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index 0bb992a..fe8bd40 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -283,6 +283,7 @@ "../javatests/src/org/chromium/android_webview/test/services/VisualStateCallbackTest.java", "../javatests/src/org/chromium/android_webview/test/ui/util/UnuploadedFilesStateLoaderTest.java", "../javatests/src/org/chromium/android_webview/test/ui/util/UploadedCrashesInfoLoaderTest.java", + "../javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashInfoCollectorTest.java", "../javatests/src/org/chromium/android_webview/test/ui/util/WebViewCrashLogParserTest.java", "../javatests/src/org/chromium/android_webview/test/util/AwQuotaManagerBridgeTestUtil.java", "../javatests/src/org/chromium/android_webview/test/util/AwTestTouchUtils.java",
diff --git a/android_webview/tools/apk_merger.py b/android_webview/tools/apk_merger.py index 7be38cdb..1e9b0858 100755 --- a/android_webview/tools/apk_merger.py +++ b/android_webview/tools/apk_merger.py
@@ -210,8 +210,6 @@ def main(): - # TODO(cjgrant): Remove obsolete arguments once the build scripts stop - # specifying them. parser = argparse.ArgumentParser( description='Merge a 32-bit APK into a 64-bit APK') # Using type=os.path.abspath converts file paths to absolute paths so that @@ -223,22 +221,13 @@ parser.add_argument('--keystore_path', required=True, type=os.path.abspath) parser.add_argument('--key_name', required=True) parser.add_argument('--key_password', required=True) - parser.add_argument('--component-build', action='store_true') - parser.add_argument('--shared_library') - parser.add_argument('--page-align-shared-libraries', action='store_true', - help='Obsolete, but remains for backwards compatibility') parser.add_argument('--uncompress-shared-libraries', action='store_true') parser.add_argument('--bundle', action='store_true') parser.add_argument('--debug', action='store_true') + # This option shall only used in debug build, see http://crbug.com/631494. parser.add_argument('--ignore-classes-dex', action='store_true') parser.add_argument('--has-unwind-cfi', action='store_true', help='Specifies if the 32-bit apk has unwind_cfi file') - parser.add_argument('--loadable_module_32', action='append', default=[], - help='Use for each 32-bit library added via ' - 'loadable_modules') - parser.add_argument('--loadable_module_64', action='append', default=[], - help='Use for each 64-bit library added via ' - 'loadable_modules') args = parser.parse_args() if (args.zipalign_path is not None and
diff --git a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt index ecb530b..237cc531 100644 --- a/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt +++ b/android_webview/tools/system_webview_shell/test/data/webexposed/not-webview-exposed.txt
@@ -123,8 +123,8 @@ # support_webgl2_compute_context not supported on android, crbug.com/865569 interface WebGL2ComputeRenderingContext -# Viz-dependent interfaces (OffscreenCanvas) are not supported on Webview yet. -interfaces: interface OffscreenCanvasRenderingContext2D +# Viz-dependent interfaces (OffscreenCanvas) are not supported on WebView yet. +interface OffscreenCanvasRenderingContext2D interface OffscreenCanvas : EventTarget interface HTMLCanvasElement : HTMLElement method transferControlToOffscreen
diff --git a/ash/app_list/test/app_list_test_helper.cc b/ash/app_list/test/app_list_test_helper.cc index 351696b..7b0bbc7 100644 --- a/ash/app_list/test/app_list_test_helper.cc +++ b/ash/app_list/test/app_list_test_helper.cc
@@ -26,12 +26,7 @@ } AppListTestHelper::~AppListTestHelper() { - // |app_list_controller_| could be released before Shell in KioskNextShell - // tests. - if (app_list_controller_ && - app_list_controller_ == Shell::Get()->app_list_controller()) { - app_list_controller_->SetClient(nullptr); - } + app_list_controller_->SetClient(nullptr); } void AppListTestHelper::WaitUntilIdle() {
diff --git a/ash/public/cpp/tablet_mode.cc b/ash/public/cpp/tablet_mode.cc index 7d65108..9d0957b 100644 --- a/ash/public/cpp/tablet_mode.cc +++ b/ash/public/cpp/tablet_mode.cc
@@ -26,7 +26,8 @@ g_instance = nullptr; } -TabletMode::Waiter::Waiter(bool enable) : enable_(enable) { +TabletMode::Waiter::Waiter(bool enable) + : enable_(enable), run_loop_(base::RunLoop::Type::kNestableTasksAllowed) { if (TabletMode::Get()->InTabletMode() == enable_) run_loop_.Quit(); else
diff --git a/ash/shelf/home_button_controller.cc b/ash/shelf/home_button_controller.cc index bdbef0b..cd31b2a 100644 --- a/ash/shelf/home_button_controller.cc +++ b/ash/shelf/home_button_controller.cc
@@ -46,9 +46,7 @@ : button_(button) { DCHECK(button_); Shell* shell = Shell::Get(); - // AppListController is only available in non-KioskNext sessions. - if (shell->app_list_controller()) - shell->app_list_controller()->AddObserver(this); + shell->app_list_controller()->AddObserver(this); shell->session_controller()->AddObserver(this); shell->tablet_mode_controller()->AddObserver(this); VoiceInteractionController::Get()->AddLocalObserver(this);
diff --git a/ash/shelf/shelf.cc b/ash/shelf/shelf.cc index c08f3c6..fc753de 100644 --- a/ash/shelf/shelf.cc +++ b/ash/shelf/shelf.cc
@@ -289,8 +289,7 @@ } void Shelf::ProcessMouseWheelEvent(const ui::MouseWheelEvent& event) { - if (Shell::Get()->app_list_controller()) - Shell::Get()->app_list_controller()->ProcessMouseWheelEvent(event); + Shell::Get()->app_list_controller()->ProcessMouseWheelEvent(event); } void Shelf::AddObserver(ShelfObserver* observer) {
diff --git a/ash/shelf/shelf_application_menu_model.cc b/ash/shelf/shelf_application_menu_model.cc index bfb3691..7219335 100644 --- a/ash/shelf/shelf_application_menu_model.cc +++ b/ash/shelf/shelf_application_menu_model.cc
@@ -39,13 +39,11 @@ DCHECK(IsCommandIdEnabled(command_id)); // Have the delegate execute its own custom command id for the given item. if (delegate_) { - if (Shell::Get()->app_list_controller()) { - // Record app launch when selecting window to open from disambiguation - // menu. - Shell::Get()->app_list_controller()->RecordShelfAppLaunched( - base::nullopt /* recorded_app_list_view_state */, - base::nullopt /* recorded_home_launcher_shown */); - } + // Record app launch when selecting window to open from disambiguation + // menu. + Shell::Get()->app_list_controller()->RecordShelfAppLaunched( + base::nullopt /* recorded_app_list_view_state */, + base::nullopt /* recorded_home_launcher_shown */); // The display hosting the menu is irrelevant, windows activate in-place. delegate_->ExecuteCommand(false /*from_context_menu*/, command_id,
diff --git a/ash/shelf/shelf_context_menu_model.cc b/ash/shelf/shelf_context_menu_model.cc index 4aa518e..c3f31fe 100644 --- a/ash/shelf/shelf_context_menu_model.cc +++ b/ash/shelf/shelf_context_menu_model.cc
@@ -126,8 +126,7 @@ break; default: if (delegate_) { - if (app_list::IsCommandIdAnAppLaunch(command_id) && - shell->app_list_controller()) { + if (app_list::IsCommandIdAnAppLaunch(command_id)) { shell->app_list_controller()->RecordShelfAppLaunched( base::nullopt /* recorded_app_list_view_state */, base::nullopt /* recorded_home_launcher_shown */);
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 0044b74..2156d941 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -265,8 +265,7 @@ void ShelfLayoutManager::InitObservers() { Shell::Get()->AddShellObserver(this); Shell::Get()->overview_controller()->AddObserver(this); - if (Shell::Get()->app_list_controller()) - Shell::Get()->app_list_controller()->AddObserver(this); + Shell::Get()->app_list_controller()->AddObserver(this); Shell::Get() ->home_screen_controller() ->home_launcher_gesture_handler() @@ -1644,8 +1643,6 @@ shelf_background_type_before_drag_ = shelf_background_type_; drag_status_ = kDragAppListInProgress; - // TODO(michaelpg): Simplify gesture drag logic and remove these DCHECKs. - DCHECK(Shell::Get()->app_list_controller()); Shell::Get()->app_list_controller()->Show( display::Screen::GetScreen() ->GetDisplayNearestWindow(shelf_widget_->GetNativeWindow()) @@ -1683,7 +1680,6 @@ if (drag_status_ == kDragAppListInProgress) { // Dismiss the app list if the shelf changed to vertical alignment during // dragging. - DCHECK(Shell::Get()->app_list_controller()); if (!shelf_->IsHorizontalAlignment()) { Shell::Get()->app_list_controller()->DismissAppList(); launcher_above_shelf_bottom_amount_ = 0.f; @@ -1739,7 +1735,6 @@ drag_status_ = kDragNone; return; } - DCHECK(Shell::Get()->app_list_controller()); using ash::AppListViewState; AppListViewState app_list_state = @@ -1761,10 +1756,8 @@ DCHECK(home_launcher_handler); if (home_launcher_handler->IsDragInProgress()) home_launcher_handler->Cancel(); - else { - DCHECK(Shell::Get()->app_list_controller()); + else Shell::Get()->app_list_controller()->DismissAppList(); - } } else { // Set |drag_status_| to kDragCancelInProgress to set the // auto hide state to |drag_auto_hide_state_|, which is the
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc index fe54638..b90ebe5 100644 --- a/ash/shelf/shelf_view.cc +++ b/ash/shelf/shelf_view.cc
@@ -656,12 +656,10 @@ // Record the current AppListViewState to be used later for metrics. The // AppListViewState will change on app launch, so this will record the // AppListViewState before the app was launched. - if (Shell::Get()->app_list_controller()) { - recorded_app_list_view_state_ = - Shell::Get()->app_list_controller()->GetAppListViewState(); - recorded_home_launcher_shown_ = - Shell::Get()->app_list_controller()->presenter()->home_launcher_shown(); - } + recorded_app_list_view_state_ = + Shell::Get()->app_list_controller()->GetAppListViewState(); + recorded_home_launcher_shown_ = + Shell::Get()->app_list_controller()->presenter()->home_launcher_shown(); // Run AfterItemSelected directly if the item has no delegate (ie. in tests). const ShelfItem& item = model_->items()[last_pressed_index_]; @@ -2162,9 +2160,8 @@ shelf_button_pressed_metric_tracker_.ButtonPressed(*event, sender, action); // Record AppList metric for any action considered an app launch. - if ((action == SHELF_ACTION_NEW_WINDOW_CREATED || - action == SHELF_ACTION_WINDOW_ACTIVATED) && - Shell::Get()->app_list_controller()) { + if (action == SHELF_ACTION_NEW_WINDOW_CREATED || + action == SHELF_ACTION_WINDOW_ACTIVATED) { Shell::Get()->app_list_controller()->RecordShelfAppLaunched( recorded_app_list_view_state_, recorded_home_launcher_shown_); }
diff --git a/ash/shell.cc b/ash/shell.cc index 8a20576..6c5c44d 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -481,12 +481,6 @@ source_type); } -void Shell::RemoveAppListController() { - // AppListController must no longer be the HomeScreenController delegate. - DCHECK_NE(home_screen_controller_->delegate(), app_list_controller_.get()); - app_list_controller_.reset(); -} - void Shell::AddShellObserver(ShellObserver* observer) { shell_observers_.AddObserver(observer); }
diff --git a/ash/shell.h b/ash/shell.h index cf48892..1bf047f 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -533,9 +533,6 @@ void ShowContextMenu(const gfx::Point& location_in_screen, ui::MenuSourceType source_type); - // Removes the AppListController. - void RemoveAppListController(); - void AddShellObserver(ShellObserver* observer); void RemoveShellObserver(ShellObserver* observer);
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc index 1df88147..3d910d5 100644 --- a/ash/wm/overview/overview_session.cc +++ b/ash/wm/overview/overview_session.cc
@@ -830,7 +830,6 @@ // overview + applist case. Shell* shell = Shell::Get(); if (!shell->tablet_mode_controller()->InTabletMode() && - shell->app_list_controller() && shell->app_list_controller()->IsVisible()) { return; }
diff --git a/base/android/linker/DEPS b/base/android/linker/DEPS index 15c3afb..43e87cc4 100644 --- a/base/android/linker/DEPS +++ b/base/android/linker/DEPS
@@ -1,4 +1,6 @@ include_rules = [ - # This code cannot depend on anything from base/ + # This code cannot depend on anything from base/, except for the current + # directory. "-base", + "+base/android/linker", ]
diff --git a/base/android/linker/legacy_linker_jni.cc b/base/android/linker/legacy_linker_jni.cc index a98ff01..eca04e9 100644 --- a/base/android/linker/legacy_linker_jni.cc +++ b/base/android/linker/legacy_linker_jni.cc
@@ -8,7 +8,7 @@ // This source code *cannot* depend on anything from base/ or the C++ // STL, to keep the final library small, and avoid ugly dependency issues. -#include "legacy_linker_jni.h" +#include "base/android/linker/legacy_linker_jni.h" #include <crazy_linker.h> #include <fcntl.h> @@ -18,7 +18,7 @@ #include <stdlib.h> #include <unistd.h> -#include "linker_jni.h" +#include "base/android/linker/linker_jni.h" namespace chromium_android_linker { namespace {
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc index 39711e0..d761e89 100644 --- a/base/android/linker/linker_jni.cc +++ b/base/android/linker/linker_jni.cc
@@ -12,15 +12,15 @@ // This source code *cannot* depend on anything from base/ or the C++ // STL, to keep the final library small, and avoid ugly dependency issues. -#include "linker_jni.h" +#include "base/android/linker/linker_jni.h" #include <jni.h> #include <stdlib.h> #include <string.h> #include <sys/mman.h> -#include "legacy_linker_jni.h" -#include "modern_linker_jni.h" +#include "base/android/linker/legacy_linker_jni.h" +#include "base/android/linker/modern_linker_jni.h" namespace chromium_android_linker {
diff --git a/base/android/linker/modern_linker_jni.cc b/base/android/linker/modern_linker_jni.cc index 284d33b..75091df6 100644 --- a/base/android/linker/modern_linker_jni.cc +++ b/base/android/linker/modern_linker_jni.cc
@@ -7,7 +7,7 @@ // This source code *cannot* depend on anything from base/ or the C++ // STL, to keep the final library small, and avoid ugly dependency issues. -#include "modern_linker_jni.h" +#include "base/android/linker/modern_linker_jni.h" #include <dlfcn.h> #include <errno.h> @@ -23,7 +23,17 @@ #include <unistd.h> #include <android/dlext.h> -#include "linker_jni.h" +#include "base/android/linker/linker_jni.h" + +// From //base/posix/eintr_wrapper.h, but we don't want to depend on //base. +#define HANDLE_EINTR(x) \ + ({ \ + decltype(x) eintr_wrapper_result; \ + do { \ + eintr_wrapper_result = (x); \ + } while (eintr_wrapper_result == -1 && errno == EINTR); \ + eintr_wrapper_result; \ + }) // Not defined on all platforms. As this linker is only supported on ARM32/64, // x86/x86_64 and MIPS, page size is always 4k. @@ -182,35 +192,6 @@ ScopedAnonymousMmap& operator=(const ScopedAnonymousMmap&) = delete; }; -// Makes sure the file descriptor is closed unless |Release()| is called. -class ScopedFileDescriptor { - public: - ScopedFileDescriptor(int fd) : fd_(fd), owned_(true) {} - ~ScopedFileDescriptor() { - if (owned_) - Close(); - } - ScopedFileDescriptor(ScopedFileDescriptor&& o) - : fd_(o.fd_), owned_(o.owned_) { - o.owned_ = false; - } - int get() const { return fd_; } - void Release() { owned_ = false; } - void Close() { - if (fd_ != -1) - close(fd_); - owned_ = false; - } - - private: - const int fd_; - bool owned_; - - // Move only. - ScopedFileDescriptor(const ScopedFileDescriptor&) = delete; - ScopedFileDescriptor& operator=(const ScopedFileDescriptor&) = delete; -}; - // Reserves an address space range, starting at |address|. // If successful, returns a valid mapping, otherwise returns an empty one. ScopedAnonymousMmap ScopedAnonymousMmap::ReserveAtAddress(void* address, @@ -230,6 +211,77 @@ return {actual_address, size}; } +// Makes sure the file descriptor is closed unless |Release()| is called. +class ScopedFileDescriptor { + public: + static ScopedFileDescriptor Open(const String& path); + + ~ScopedFileDescriptor() { + if (owned_) + Close(); + } + + ScopedFileDescriptor(ScopedFileDescriptor&& o) + : fd_(o.fd_), owned_(o.owned_) { + o.owned_ = false; + } + + int get() const { return fd_; } + + bool IsValid() const { return fd_ != -1; } + + int Release() { + owned_ = false; + return fd_; + } + + bool ReopenReadOnly(const String& original_path); + + private: + explicit ScopedFileDescriptor(int fd) : fd_(fd), owned_(true) {} + void Close() { + if (IsValid()) + close(fd_); + owned_ = false; + } + + int fd_; + bool owned_; + + // Move only. + ScopedFileDescriptor(const ScopedFileDescriptor&) = delete; + ScopedFileDescriptor& operator=(const ScopedFileDescriptor&) = delete; +}; + +ScopedFileDescriptor ScopedFileDescriptor::Open(const String& path) { + int flags = O_RDWR | O_CREAT | O_EXCL; + int mode = S_IRUSR | S_IWUSR; + int fd = HANDLE_EINTR(open(path.c_str(), flags, mode)); + return ScopedFileDescriptor{fd}; +} + +// Reopens |this| that was initially opened from |original_path| as a read-only +// fd. +// Deletes the file in the process, and returns true for success. +bool ScopedFileDescriptor::ReopenReadOnly(const String& original_path) { + const char* filepath = original_path.c_str(); + Close(); + fd_ = HANDLE_EINTR(open(filepath, O_RDONLY)); + if (!IsValid()) { + LOG_ERROR("open: %s: %s", original_path.c_str(), strerror(errno)); + return false; + } + + // Delete the directory entry for the RELRO file. The fd we hold ensures + // that its data remains intact. + if (unlink(filepath) == -1) { + LOG_ERROR("unlink: %s: %s", filepath, strerror(errno)); + return false; + } + + return true; +} + // Returns the actual size of the library loaded at |addr| in |load_size|, and // the min vaddr in |min_vaddr|. Returns false if the library appears not to be // loaded. @@ -253,28 +305,6 @@ return true; } -// Reopens |fd| that was initially opened from |path| as a read-only fd. -// Deletes the file in the process, and returns the new read only file -// descriptor in case of success, -1 otherwise. -ScopedFileDescriptor ReopenReadOnly(const String& path, - ScopedFileDescriptor original_fd) { - const char* filepath = path.c_str(); - original_fd.Close(); - ScopedFileDescriptor scoped_fd{open(filepath, O_RDONLY)}; - if (scoped_fd.get() == -1) { - LOG_ERROR("open: %s: %s", path.c_str(), strerror(errno)); - return -1; - } - - // Delete the directory entry for the RELRO file. The fd we hold ensures - // that its data remains intact. - if (unlink(filepath) == -1) { - LOG_ERROR("unlink: %s: %s", filepath, strerror(errno)); - return -1; - } - return scoped_fd; -} - // Resizes the address space reservation to the actual required size. // Failure here is only a warning, as at worst this wastes virtual address // space, not actual memory. @@ -341,9 +371,8 @@ return -1; unlink(relocations_path.c_str()); - ScopedFileDescriptor relro_fd = ScopedFileDescriptor{open( - relocations_path.c_str(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)}; - if (relro_fd.get() == -1) { + ScopedFileDescriptor relro_fd = ScopedFileDescriptor::Open(relocations_path); + if (!relro_fd.IsValid()) { LOG_ERROR("open: %s: %s", relocations_path.c_str(), strerror(errno)); return -1; } @@ -367,10 +396,8 @@ unlink(relocations_path.c_str()); return false; } - ScopedFileDescriptor scoped_fd = - ReopenReadOnly(relocations_path, std::move(relro_fd)); - scoped_fd.Release(); - return scoped_fd.get(); + relro_fd.ReopenReadOnly(relocations_path); + return relro_fd.Release(); } // Load the library at |path| at address |wanted_address| if possible, and
diff --git a/base/debug/profiler.cc b/base/debug/profiler.cc index 3c651a3..ede6467e 100644 --- a/base/debug/profiler.cc +++ b/base/debug/profiler.cc
@@ -158,7 +158,7 @@ base::win::PEImage image(CURRENT_MODULE()); FunctionSearchContext ctx = { function_name, NULL }; - image.EnumImportChunks(FindResolutionFunctionInImports, &ctx); + image.EnumImportChunks(FindResolutionFunctionInImports, &ctx, nullptr); return reinterpret_cast<FunctionType>(ctx.function); }
diff --git a/base/files/file_util.cc b/base/files/file_util.cc index e6e84a2..f11f456c 100644 --- a/base/files/file_util.cc +++ b/base/files/file_util.cc
@@ -281,20 +281,34 @@ } int GetUniquePathNumber(const FilePath& path, - const FilePath::StringType& suffix) { - bool have_suffix = !suffix.empty(); - if (!PathExists(path) && - (!have_suffix || !PathExists(FilePath(path.value() + suffix)))) { - return 0; - } + FilePath::StringPieceType suffix) { + // Storage for use by is_unique to reduce heap churn when looping. + FilePath::StringType path_with_suffix; - FilePath new_path; - for (int count = 1; count <= kMaxUniqueFiles; ++count) { - new_path = path.InsertBeforeExtensionASCII(StringPrintf(" (%d)", count)); - if (!PathExists(new_path) && - (!have_suffix || !PathExists(FilePath(new_path.value() + suffix)))) { - return count; + // A function that returns true if |candidate| is unique with and without an + // optional suffix. + const auto is_unique = [suffix, + &path_with_suffix](const base::FilePath& candidate) { + if (!PathExists(candidate)) { + if (suffix.empty()) + return true; + path_with_suffix = candidate.value(); + suffix.AppendToString(&path_with_suffix); + if (!PathExists(FilePath(path_with_suffix))) + return true; } + return false; + }; + + if (is_unique(path)) + return 0; + + std::string number; + for (int count = 1; count <= kMaxUniqueFiles; ++count) { + StringAppendF(&number, " (%d)", count); + if (is_unique(path.InsertBeforeExtensionASCII(number))) + return count; + number.clear(); } return -1; @@ -302,7 +316,7 @@ FilePath GetUniquePath(const FilePath& path) { FilePath unique_path = path; - int uniquifier = GetUniquePathNumber(path, FilePath::StringType()); + int uniquifier = GetUniquePathNumber(path); if (uniquifier > 0) { unique_path = unique_path.InsertBeforeExtensionASCII( StringPrintf(" (%d)", uniquifier));
diff --git a/base/files/file_util.h b/base/files/file_util.h index 0987b7b..fc2f443 100644 --- a/base/files/file_util.h +++ b/base/files/file_util.h
@@ -401,8 +401,9 @@ // unique. If |path| does not exist, 0 is returned. If it fails to find such // a number, -1 is returned. If |suffix| is not empty, also checks the // existence of it with the given suffix. -BASE_EXPORT int GetUniquePathNumber(const FilePath& path, - const FilePath::StringType& suffix); +BASE_EXPORT int GetUniquePathNumber( + const FilePath& path, + FilePath::StringPieceType suffix = FilePath::StringPieceType()); // If file at |path| already exists, modifies filename portion of |path| to // return unique path.
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc index 21cefcc4..64de4d0 100644 --- a/base/files/file_util_unittest.cc +++ b/base/files/file_util_unittest.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/files/file_util.h" + #include <stddef.h> #include <stdint.h> #include <stdio.h> @@ -23,7 +25,6 @@ #include "base/files/file.h" #include "base/files/file_enumerator.h" #include "base/files/file_path.h" -#include "base/files/file_util.h" #include "base/files/scoped_file.h" #include "base/files/scoped_temp_dir.h" #include "base/guid.h" @@ -37,6 +38,7 @@ #include "base/test/test_timeouts.h" #include "base/threading/platform_thread.h" #include "base/threading/thread.h" +#include "base/time/time.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/multiprocess_func_list.h" @@ -3871,6 +3873,48 @@ } #endif +#if !defined(OS_NACL_NONSFI) +TEST_F(FileUtilTest, GetUniquePathNumber) { + static constexpr FilePath::StringPieceType kSomeFile(FPL("SomeFile.txt")); + static constexpr FilePath::StringPieceType kSomeFileOne( + FPL("SomeFile (1).txt")); + static constexpr FilePath::StringPieceType kSomeSuffix(FPL(".SUFFIX")); + + const FilePath& temp_dir = temp_dir_.GetPath(); + + // The dir is empty to start with. + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile)), 0); + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 0); + + // Manufacture a collision with the suffixed file. + FilePath::StringType path = kSomeFile.as_string(); + kSomeSuffix.AppendToString(&path); + ASSERT_EQ(WriteFile(temp_dir.Append(path), "hi", 2), 2); + // No collision unsuffixed. + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile)), 0); + // But there is with the suffix. + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 1); + ASSERT_TRUE(DeleteFile(temp_dir.Append(path), false)); + + // Manufacture a collision with the unsuffixed file. + ASSERT_EQ(WriteFile(temp_dir.Append(kSomeFile), "hi", 2), 2); + // Both collide. + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile)), 1); + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 1); + + // Now with the unsuffixed collision, manufacture a suffixed collision with + // the number '1'. + path = kSomeFileOne.as_string(); + kSomeSuffix.AppendToString(&path); + ASSERT_EQ(WriteFile(temp_dir.Append(path), "hi", 2), 2); + EXPECT_EQ(GetUniquePathNumber(temp_dir.Append(kSomeFile), kSomeSuffix), 2); + + // Clean up. + ASSERT_TRUE(DeleteFile(temp_dir.Append(path), false)); + ASSERT_TRUE(DeleteFile(temp_dir.Append(kSomeFile), false)); +} +#endif // !defined(OS_NACL_NONSFI) + // Test that temp files obtained racily are all unique (no interference between // threads). Mimics file operations in DoLaunchChildTestProcess() to rule out // thread-safety issues @ https://crbug.com/826408#c17.
diff --git a/base/task/task_traits.h b/base/task/task_traits.h index 32be5e3..68d7503 100644 --- a/base/task/task_traits.h +++ b/base/task/task_traits.h
@@ -32,17 +32,18 @@ enum class TaskPriority : uint8_t { // This will always be equal to the lowest priority available. LOWEST = 0, - // This task will only start running when machine resources are available. - // Dependending on the ThreadPolicy, it may run on a thread that is likely to - // be descheduled when higher priority work arrives (in this process or - // another). + // This task will only start running when machine resources are available. The + // application may preempt the task if it expects that resources will soon be + // needed by work of higher priority. Dependending on the ThreadPolicy, the + // task may run on a thread that is likely to be descheduled when higher + // priority work arrives (in this process or another). // // Examples: // - Reporting metrics. // - Persisting data to disk. // - Loading data that is required for a potential future user interaction - // (Note: Use CreateUpdateableSequencedTaskRunner() to increase - // the priority when that user interactions happens). + // (Note: Use CreateUpdateableSequencedTaskRunner() to increase the priority + // when that user interactions happens). BEST_EFFORT = LOWEST, // The result of this task is visible to the user (in the UI or as a
diff --git a/base/win/BUILD.gn b/base/win/BUILD.gn index 19c2982..e6e27510 100644 --- a/base/win/BUILD.gn +++ b/base/win/BUILD.gn
@@ -26,6 +26,7 @@ static_library("pe_image") { sources = [ + "current_module.h", "pe_image.cc", "pe_image.h", ]
diff --git a/base/win/iat_patch_function.cc b/base/win/iat_patch_function.cc index 3cc747b..f1f28c27 100644 --- a/base/win/iat_patch_function.cc +++ b/base/win/iat_patch_function.cc
@@ -24,9 +24,9 @@ }; void* GetIATFunction(IMAGE_THUNK_DATA* iat_thunk) { - if (NULL == iat_thunk) { + if (!iat_thunk) { NOTREACHED(); - return NULL; + return nullptr; } // Works around the 64 bit portability warning: @@ -48,22 +48,20 @@ InterceptFunctionInformation* intercept_information = reinterpret_cast<InterceptFunctionInformation*>(cookie); - if (NULL == intercept_information) { + if (!intercept_information) { NOTREACHED(); return false; } DCHECK(module); - if ((0 == lstrcmpiA(module, intercept_information->imported_from_module)) && - (NULL != name) && - (0 == lstrcmpiA(name, intercept_information->function_name))) { + if (name && (0 == lstrcmpiA(name, intercept_information->function_name))) { // Save the old pointer. - if (NULL != intercept_information->old_function) { + if (intercept_information->old_function) { *(intercept_information->old_function) = GetIATFunction(iat); } - if (NULL != intercept_information->iat_thunk) { + if (intercept_information->iat_thunk) { *(intercept_information->iat_thunk) = iat; } @@ -104,8 +102,8 @@ const char* function_name, void* new_function, void** old_function, IMAGE_THUNK_DATA** iat_thunk) { - if ((NULL == module_handle) || (NULL == imported_from_module) || - (NULL == function_name) || (NULL == new_function)) { + if (!module_handle || !imported_from_module || !function_name || + !new_function) { NOTREACHED(); return ERROR_INVALID_PARAMETER; } @@ -127,10 +125,11 @@ // First go through the IAT. If we don't find the import we are looking // for in IAT, search delay import table. - target_image.EnumAllImports(InterceptEnumCallback, &intercept_information); + target_image.EnumAllImports(InterceptEnumCallback, &intercept_information, + imported_from_module); if (!intercept_information.finished_operation) { - target_image.EnumAllDelayImports(InterceptEnumCallback, - &intercept_information); + target_image.EnumAllDelayImports( + InterceptEnumCallback, &intercept_information, imported_from_module); } return intercept_information.return_code; @@ -147,8 +146,7 @@ DWORD RestoreImportedFunction(void* intercept_function, void* original_function, IMAGE_THUNK_DATA* iat_thunk) { - if ((NULL == intercept_function) || (NULL == original_function) || - (NULL == iat_thunk)) { + if (!intercept_function || !original_function || !iat_thunk) { NOTREACHED(); return ERROR_INVALID_PARAMETER; } @@ -166,15 +164,10 @@ } // namespace -IATPatchFunction::IATPatchFunction() - : module_handle_(NULL), - intercept_function_(NULL), - original_function_(NULL), - iat_thunk_(NULL) { -} +IATPatchFunction::IATPatchFunction() = default; IATPatchFunction::~IATPatchFunction() { - if (NULL != intercept_function_) { + if (intercept_function_) { DWORD error = Unpatch(); DCHECK_EQ(static_cast<DWORD>(NO_ERROR), error); } @@ -185,7 +178,7 @@ const char* function_name, void* new_function) { HMODULE module_handle = LoadLibraryW(module); - if (module_handle == NULL) { + if (!module_handle) { NOTREACHED(); return GetLastError(); } @@ -205,9 +198,9 @@ const char* imported_from_module, const char* function_name, void* new_function) { - DCHECK_EQ(static_cast<void*>(NULL), original_function_); - DCHECK_EQ(static_cast<IMAGE_THUNK_DATA*>(NULL), iat_thunk_); - DCHECK_EQ(static_cast<void*>(NULL), intercept_function_); + DCHECK_EQ(nullptr, original_function_); + DCHECK_EQ(nullptr, iat_thunk_); + DCHECK_EQ(nullptr, intercept_function_); DCHECK(module); DWORD error = InterceptImportedFunction(module, @@ -239,10 +232,10 @@ // not going to be any safer if (module_handle_) FreeLibrary(module_handle_); - module_handle_ = NULL; - intercept_function_ = NULL; - original_function_ = NULL; - iat_thunk_ = NULL; + module_handle_ = nullptr; + intercept_function_ = nullptr; + original_function_ = nullptr; + iat_thunk_ = nullptr; return error; }
diff --git a/base/win/iat_patch_function.h b/base/win/iat_patch_function.h index 86ad295..22655a0 100644 --- a/base/win/iat_patch_function.h +++ b/base/win/iat_patch_function.h
@@ -67,10 +67,10 @@ private: - HMODULE module_handle_; - void* intercept_function_; - void* original_function_; - IMAGE_THUNK_DATA* iat_thunk_; + HMODULE module_handle_ = nullptr; + void* intercept_function_ = nullptr; + void* original_function_ = nullptr; + IMAGE_THUNK_DATA* iat_thunk_ = nullptr; DISALLOW_COPY_AND_ASSIGN(IATPatchFunction); };
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc index 5056915..b08fe0c 100644 --- a/base/win/pe_image.cc +++ b/base/win/pe_image.cc
@@ -5,9 +5,12 @@ // This file implements PEImage, a generic class to manipulate PE files. // This file was adapted from GreenBorder's Code. +#include "base/win/pe_image.h" + +#include <delayimp.h> #include <stddef.h> -#include "base/win/pe_image.h" +#include "base/win/current_module.h" namespace base { namespace win { @@ -139,8 +142,8 @@ for (int i = 0; i < num_sections; i++) { PIMAGE_SECTION_HEADER section = GetSectionHeader(i); - if (0 == _strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name, - sizeof(section->Name))) { + if (_strnicmp(reinterpret_cast<LPCSTR>(section->Name), section_name, + sizeof(section->Name)) == 0) { ret = section; break; } @@ -382,7 +385,8 @@ } bool PEImage::EnumImportChunks(EnumImportChunksFunction callback, - PVOID cookie) const { + PVOID cookie, + LPCSTR target_module_name) const { DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_IMPORT); PIMAGE_IMPORT_DESCRIPTOR import = GetFirstImportChunk(); @@ -396,8 +400,11 @@ PIMAGE_THUNK_DATA iat = reinterpret_cast<PIMAGE_THUNK_DATA>( RVAToAddr(import->FirstThunk)); - if (!callback(*this, module_name, name_table, iat, cookie)) - return false; + if (target_module_name == nullptr || + (lstrcmpiA(module_name, target_module_name) == 0)) { + if (!callback(*this, module_name, name_table, iat, cookie)) + return false; + } } return true; @@ -432,13 +439,16 @@ return true; } -bool PEImage::EnumAllImports(EnumImportsFunction callback, PVOID cookie) const { +bool PEImage::EnumAllImports(EnumImportsFunction callback, + PVOID cookie, + LPCSTR target_module_name) const { EnumAllImportsStorage temp = { callback, cookie }; - return EnumImportChunks(ProcessImportChunk, &temp); + return EnumImportChunks(ProcessImportChunk, &temp, target_module_name); } bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback, - PVOID cookie) const { + PVOID cookie, + LPCSTR target_module_name) const { PVOID directory = GetImageDirectoryEntryAddr( IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); DWORD size = GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT); @@ -474,9 +484,24 @@ static_cast<uintptr_t>(delay_descriptor->rvaIAT)); } - if (!callback(*this, delay_descriptor, module_name, name_table, iat, - cookie)) - return false; + if (target_module_name == nullptr || + (lstrcmpiA(module_name, target_module_name) == 0)) { + if (target_module_name) { + // Ensure all imports are properly loaded for the target module so that + // the callback is operating on a fully-realized set of imports. + // This call only loads the imports for the module where this code is + // executing, so it is only helpful or meaningful to do this if the + // current module is the module whose IAT we are enumerating. + // Use the module_name as retrieved from the IAT because this method + // is case sensitive. + if (module_ == CURRENT_MODULE()) + ::__HrLoadAllImportsForDll(module_name); + } + + if (!callback(*this, delay_descriptor, module_name, name_table, iat, + cookie)) + return false; + } } return true; @@ -519,9 +544,11 @@ } bool PEImage::EnumAllDelayImports(EnumImportsFunction callback, - PVOID cookie) const { + PVOID cookie, + LPCSTR target_module_name) const { EnumAllImportsStorage temp = { callback, cookie }; - return EnumDelayImportChunks(ProcessDelayImportChunk, &temp); + return EnumDelayImportChunks(ProcessDelayImportChunk, &temp, + target_module_name); } bool PEImage::VerifyMagic() const {
diff --git a/base/win/pe_image.h b/base/win/pe_image.h index 311fde5..8905b68 100644 --- a/base/win/pe_image.h +++ b/base/win/pe_image.h
@@ -187,12 +187,20 @@ // Enumerates PE imports. // cookie is a generic cookie to pass to the callback. // Returns true on success. - bool EnumAllImports(EnumImportsFunction callback, PVOID cookie) const; + // Use |target_module_name| to ensure the callback is only invoked for the + // specified module. + bool EnumAllImports(EnumImportsFunction callback, + PVOID cookie, + LPCSTR target_module_name) const; // Enumerates PE import blocks. // cookie is a generic cookie to pass to the callback. // Returns true on success. - bool EnumImportChunks(EnumImportChunksFunction callback, PVOID cookie) const; + // Use |target_module_name| to ensure the callback is only invoked for the + // specified module. + bool EnumImportChunks(EnumImportChunksFunction callback, + PVOID cookie, + LPCSTR target_module_name) const; // Enumerates the imports from a single PE import block. // cookie is a generic cookie to pass to the callback. @@ -201,17 +209,25 @@ PIMAGE_THUNK_DATA name_table, PIMAGE_THUNK_DATA iat, PVOID cookie) const; - // Enumerates PE delay imports. // cookie is a generic cookie to pass to the callback. // Returns true on success. - bool EnumAllDelayImports(EnumImportsFunction callback, PVOID cookie) const; + // Use |target_module_name| to ensure the callback is only invoked for the + // specified module. If this parameter is non-null then all delayloaded + // imports are resolved when the target module is found. + bool EnumAllDelayImports(EnumImportsFunction callback, + PVOID cookie, + LPCSTR target_module_name) const; // Enumerates PE delay import blocks. // cookie is a generic cookie to pass to the callback. // Returns true on success. + // Use |target_module_name| to ensure the callback is only invoked for the + // specified module. If this parameter is non-null then all delayloaded + // imports are resolved when the target module is found. bool EnumDelayImportChunks(EnumDelayImportChunksFunction callback, - PVOID cookie) const; + PVOID cookie, + LPCSTR target_module_name) const; // Enumerates imports from a single PE delay import block. // cookie is a generic cookie to pass to the callback.
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc index 302c872..caf241b8d 100644 --- a/base/win/pe_image_unittest.cc +++ b/base/win/pe_image_unittest.cc
@@ -115,29 +115,29 @@ base::FilePath pe_image_test_path = GetPEImageTestPath(); #if defined(ARCH_CPU_ARM64) - const int sections = 7; - const int imports_dlls = 3; - const int delay_dlls = 2; - const int exports = 3; - const int imports = 72; - const int delay_imports = 2; - const int relocs = 740; + const int kSections = 7; + const int kImportsDlls = 3; + const int kDelayDlls = 2; + const int kExports = 3; + const int kImports = 72; + const int kDelayImports = 2; + const int kRelocs = 740; #elif defined(ARCH_CPU_64_BITS) - const int sections = 6; - const int imports_dlls = 2; - const int delay_dlls = 2; - const int exports = 3; - const int imports = 70; - const int delay_imports = 2; - const int relocs = 976; + const int kSections = 6; + const int kImportsDlls = 2; + const int kDelayDlls = 2; + const int kExports = 3; + const int kImports = 70; + const int kDelayImports = 2; + const int kRelocs = 976; #else - const int sections = 5; - const int imports_dlls = 2; - const int delay_dlls = 2; - const int exports = 3; - const int imports = 66; - const int delay_imports = 2; - const int relocs = 2114; + const int kSections = 5; + const int kImportsDlls = 2; + const int kDelayDlls = 2; + const int kExports = 3; + const int kImports = 66; + const int kDelayImports = 2; + const int kRelocs = 2114; #endif ScopedNativeLibrary module(pe_image_test_path); @@ -148,31 +148,100 @@ EXPECT_TRUE(pe.VerifyMagic()); pe.EnumSections(SectionsCallback, &count); - EXPECT_EQ(sections, count); + EXPECT_EQ(kSections, count); count = 0; - pe.EnumImportChunks(ImportChunksCallback, &count); - EXPECT_EQ(imports_dlls, count); + pe.EnumImportChunks(ImportChunksCallback, &count, nullptr); + EXPECT_EQ(kImportsDlls, count); count = 0; - pe.EnumDelayImportChunks(DelayImportChunksCallback, &count); - EXPECT_EQ(delay_dlls, count); + pe.EnumDelayImportChunks(DelayImportChunksCallback, &count, nullptr); + EXPECT_EQ(kDelayDlls, count); count = 0; pe.EnumExports(ExportsCallback, &count); - EXPECT_EQ(exports, count); + EXPECT_EQ(kExports, count); count = 0; - pe.EnumAllImports(ImportsCallback, &count); - EXPECT_EQ(imports, count); + pe.EnumAllImports(ImportsCallback, &count, nullptr); + EXPECT_EQ(kImports, count); count = 0; - pe.EnumAllDelayImports(ImportsCallback, &count); - EXPECT_EQ(delay_imports, count); + pe.EnumAllDelayImports(ImportsCallback, &count, nullptr); + EXPECT_EQ(kDelayImports, count); count = 0; pe.EnumRelocs(RelocsCallback, &count); - EXPECT_EQ(relocs, count); + EXPECT_EQ(kRelocs, count); +} + +// Tests that we are able to enumerate stuff from a PE file, and that +// the actual number of items found matches an expected value. +TEST(PEImageTest, EnumeratesPEWithTargetModule) { + base::FilePath pe_image_test_path = GetPEImageTestPath(); + const char kTargetModuleStatic[] = "user32.dll"; + const char kTargetModuleDelay[] = "cfgmgr32.dll"; + +#if defined(ARCH_CPU_ARM64) + const int kSections = 7; + const int kImportsDlls = 2; + const int kDelayDlls = 1; + const int kExports = 3; + const int kImports = 2; + const int kDelayImports = 1; + const int kRelocs = 740; +#elif defined(ARCH_CPU_64_BITS) + const int kSections = 6; + const int kImportsDlls = 1; + const int kDelayDlls = 1; + const int kExports = 3; + const int kImports = 2; + const int kDelayImports = 1; + const int kRelocs = 976; +#else + const int kSections = 5; + const int kImportsDlls = 1; + const int kDelayDlls = 1; + const int kExports = 3; + const int kImports = 2; + const int kDelayImports = 1; + const int kRelocs = 2114; +#endif + + ScopedNativeLibrary module(pe_image_test_path); + ASSERT_TRUE(module.is_valid()); + + PEImage pe(module.get()); + int count = 0; + EXPECT_TRUE(pe.VerifyMagic()); + + pe.EnumSections(SectionsCallback, &count); + EXPECT_EQ(kSections, count); + + count = 0; + pe.EnumImportChunks(ImportChunksCallback, &count, kTargetModuleStatic); + EXPECT_EQ(kImportsDlls, count); + + count = 0; + pe.EnumDelayImportChunks(DelayImportChunksCallback, &count, + kTargetModuleDelay); + EXPECT_EQ(kDelayDlls, count); + + count = 0; + pe.EnumExports(ExportsCallback, &count); + EXPECT_EQ(kExports, count); + + count = 0; + pe.EnumAllImports(ImportsCallback, &count, kTargetModuleStatic); + EXPECT_EQ(kImports, count); + + count = 0; + pe.EnumAllDelayImports(ImportsCallback, &count, kTargetModuleDelay); + EXPECT_EQ(kDelayImports, count); + + count = 0; + pe.EnumRelocs(RelocsCallback, &count); + EXPECT_EQ(kRelocs, count); } // Tests that we can locate an specific exported symbol, by name and by ordinal.
diff --git a/build/buildflag_header.gni b/build/buildflag_header.gni index 281c164..93088a5 100644 --- a/build/buildflag_header.gni +++ b/build/buildflag_header.gni
@@ -31,8 +31,8 @@ # # const char kSpamServerUrl[] = BUILDFLAG(SPAM_SERVER_URL); # -# There will no #define called ENABLE_FOO so if you accidentally test for that -# in an ifdef it will always be negative. +# There will be no #define called ENABLE_FOO so if you accidentally test for +# that in an ifdef it will always be negative. # # # Template parameters
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 7bfe3fe..3eaee065 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8905202830898033264 \ No newline at end of file +8905148419810812688 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index 246526a5..1429bc6 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8905202810180352016 \ No newline at end of file +8905148320271116416 \ No newline at end of file
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index cf7e11c2..51d7bbe9 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -103,6 +103,7 @@ "java/src/org/chromium/chrome/browser/background_sync/BackgroundSyncPwaDetector.java", "java/src/org/chromium/chrome/browser/background_sync/PeriodicBackgroundSyncChromeWakeUpTask.java", "java/src/org/chromium/chrome/browser/background_task_scheduler/NativeBackgroundTask.java", + "java/src/org/chromium/chrome/browser/background_task_scheduler/ChromeBackgroundTaskFactory.java", "java/src/org/chromium/chrome/browser/banners/AppBannerManager.java", "java/src/org/chromium/chrome/browser/banners/AppBannerUiDelegateAndroid.java", "java/src/org/chromium/chrome/browser/banners/AppData.java",
diff --git a/chrome/android/chrome_junit_test_java_sources.gni b/chrome/android/chrome_junit_test_java_sources.gni index f33325f..a8076ef 100644 --- a/chrome/android/chrome_junit_test_java_sources.gni +++ b/chrome/android/chrome_junit_test_java_sources.gni
@@ -176,6 +176,7 @@ "junit/src/org/chromium/chrome/browser/send_tab_to_self/NotificationSharedPrefManagerTest.java", "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfAndroidBridgeTest.java", "junit/src/org/chromium/chrome/browser/send_tab_to_self/SendTabToSelfShareActivityTest.java", + "junit/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandlerTest.java", "junit/src/org/chromium/chrome/browser/signin/SigninManagerTest.java", "junit/src/org/chromium/chrome/browser/signin/SigninPromoUtilTest.java", "junit/src/org/chromium/chrome/browser/snackbar/SnackbarCollectionUnitTest.java",
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java index 408c2e02..555c5cb 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/AssistantBottomBarCoordinator.java
@@ -129,6 +129,15 @@ mLayoutTransition.excludeChildren(mSuggestionsCoordinator.getView(), /* exclude= */ true); mLayoutTransition.excludeChildren(mActionsCoordinator.getView(), /* exclude= */ true); + // do not animate the contents of the payment method section inside the section choice list, + // since the animation is not required and causes a rendering crash. + mLayoutTransition.excludeChildren( + mPaymentRequestCoordinator.getView() + .findViewWithTag( + AssistantTagsForTesting.PAYMENT_REQUEST_PAYMENT_METHOD_SECTION_TAG) + .findViewById(R.id.section_choice_list), + /* exclude= */ true); + // Add child views to bottom bar container. We put all child views in the scrollable // container, except the actions and suggestions. bottomBarView.addView(mHeaderCoordinator.getView(), 0);
diff --git a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java index 58595a8..e4d7ca0 100644 --- a/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java +++ b/chrome/android/features/autofill_assistant/java/src/org/chromium/chrome/browser/autofill_assistant/payment/AssistantPaymentRequestPaymentMethodSection.java
@@ -115,11 +115,8 @@ hideIfEmpty(cardExpirationView); TextView methodIncompleteView = summaryView.findViewById(R.id.incomplete_error); - if (!isComplete(method)) { - setIncompleteErrorMessage(methodIncompleteView, method); - } else { - methodIncompleteView.setVisibility(View.GONE); - } + setIncompleteErrorMessage(methodIncompleteView, method); + hideIfEmpty(methodIncompleteView); } void onProfilesChanged(List<PersonalDataManager.AutofillProfile> profiles) { @@ -167,7 +164,7 @@ mEditor.updateBillingAddressIfComplete(new AutofillAddress(mContext, profile)); } - private boolean isComplete(AutofillPaymentInstrument method) { + private boolean hasAllRequiredFields(AutofillPaymentInstrument method) { if (!method.isComplete()) { return false; } @@ -190,6 +187,11 @@ private void setIncompleteErrorMessage( TextView methodIncompleteView, AutofillPaymentInstrument method) { + if (hasAllRequiredFields(method)) { + methodIncompleteView.setText(""); + return; + } + // we have to show an error message either because the payment method is incomplete (missing // information), or because a postcode is required and the billing address does not have // one. @@ -198,7 +200,5 @@ } else { methodIncompleteView.setText(R.string.autofill_assistant_payment_information_missing); } - - methodIncompleteView.setVisibility(View.VISIBLE); } } \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java index 9fcf46b..733bfc0 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeApplication.java
@@ -32,6 +32,7 @@ import org.chromium.build.BuildHooks; import org.chromium.build.BuildHooksAndroid; import org.chromium.build.BuildHooksConfig; +import org.chromium.chrome.browser.background_task_scheduler.ChromeBackgroundTaskFactory; import org.chromium.chrome.browser.crash.ApplicationStatusTracker; import org.chromium.chrome.browser.crash.FirebaseConfig; import org.chromium.chrome.browser.crash.PureJavaExceptionHandler; @@ -47,6 +48,7 @@ import org.chromium.chrome.browser.preferences.ChromePreferenceManager; import org.chromium.chrome.browser.vr.OnExitVrRequestListener; import org.chromium.chrome.browser.vr.VrModuleProvider; +import org.chromium.components.background_task_scheduler.BackgroundTaskSchedulerFactory; import org.chromium.components.embedder_support.application.FontPreloadingWorkaround; import org.chromium.components.module_installer.ModuleInstaller; import org.chromium.ui.base.ResourceBundle; @@ -122,6 +124,10 @@ // Record via UMA all modules that have been requested and are currently installed. This // will tell us the install penetration of each module over time. ModuleInstaller.getInstance().recordModuleAvailability(); + + // Set Chrome factory for mapping BackgroundTask classes to TaskIds. + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new ChromeBackgroundTaskFactory()); } // Write installed modules to crash keys. This needs to be done as early as possible so that
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java index 48343ca..3fa12fb0c 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java
@@ -197,6 +197,7 @@ public static final String CHROME_DUET_LABELED = "ChromeDuetLabeled"; public static final String CHROME_SMART_SELECTION = "ChromeSmartSelection"; public static final String CLEAR_OLD_BROWSING_DATA = "ClearOldBrowsingData"; + public static final String CLICK_TO_CALL_OPEN_DIALER_DIRECTLY = "ClickToCallOpenDialerDirectly"; public static final String COMMAND_LINE_ON_NON_ROOTED = "CommandLineOnNonRooted"; public static final String CONTACTS_PICKER_SELECT_ALL = "ContactsPickerSelectAll"; public static final String CONTENT_SUGGESTIONS_SCROLL_TO_LOAD =
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/ChromeBackgroundTaskFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/ChromeBackgroundTaskFactory.java new file mode 100644 index 0000000..e1b1000 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/background_task_scheduler/ChromeBackgroundTaskFactory.java
@@ -0,0 +1,78 @@ +// 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.background_task_scheduler; + +import org.chromium.base.Log; +import org.chromium.chrome.browser.background_sync.BackgroundSyncBackgroundTask; +import org.chromium.chrome.browser.background_sync.PeriodicBackgroundSyncChromeWakeUpTask; +import org.chromium.chrome.browser.component_updater.UpdateTask; +import org.chromium.chrome.browser.download.DownloadResumptionBackgroundTask; +import org.chromium.chrome.browser.download.service.DownloadBackgroundTask; +import org.chromium.chrome.browser.explore_sites.ExploreSitesBackgroundTask; +import org.chromium.chrome.browser.feed.FeedRefreshTask; +import org.chromium.chrome.browser.notifications.NotificationTriggerBackgroundTask; +import org.chromium.chrome.browser.notifications.scheduler.NotificationSchedulerTask; +import org.chromium.chrome.browser.offlinepages.OfflineBackgroundTask; +import org.chromium.chrome.browser.offlinepages.prefetch.OfflineNotificationBackgroundTask; +import org.chromium.chrome.browser.offlinepages.prefetch.PrefetchBackgroundTask; +import org.chromium.chrome.browser.omaha.OmahaService; +import org.chromium.chrome.browser.services.gcm.GCMBackgroundTask; +import org.chromium.chrome.browser.webapps.WebApkUpdateTask; +import org.chromium.components.background_task_scheduler.BackgroundTask; +import org.chromium.components.background_task_scheduler.BackgroundTaskFactory; +import org.chromium.components.background_task_scheduler.TaskIds; + +/** + * Implementation of {@link BackgroundTaskFactory} for //chrome. + * Maps all task ids used in //chrome with their BackgroundTask classes. + */ +public class ChromeBackgroundTaskFactory implements BackgroundTaskFactory { + private static final String TAG = "ChromeBkgrdTaskF"; + public ChromeBackgroundTaskFactory() {} + + @Override + public BackgroundTask getBackgroundTaskFromTaskId(int taskId) { + switch (taskId) { + case TaskIds.OMAHA_JOB_ID: + return new OmahaService(); + case TaskIds.GCM_BACKGROUND_TASK_JOB_ID: + return new GCMBackgroundTask(); + case TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID: + return new OfflineBackgroundTask(); + case TaskIds.OFFLINE_PAGES_PREFETCH_JOB_ID: + return new PrefetchBackgroundTask(); + case TaskIds.OFFLINE_PAGES_PREFETCH_NOTIFICATION_JOB_ID: + return new OfflineNotificationBackgroundTask(); + case TaskIds.DOWNLOAD_SERVICE_JOB_ID: + case TaskIds.DOWNLOAD_CLEANUP_JOB_ID: + case TaskIds.DOWNLOAD_AUTO_RESUMPTION_JOB_ID: + return new DownloadBackgroundTask(); + case TaskIds.WEBAPK_UPDATE_JOB_ID: + return new WebApkUpdateTask(); + case TaskIds.DOWNLOAD_RESUMPTION_JOB_ID: + return new DownloadResumptionBackgroundTask(); + case TaskIds.FEED_REFRESH_JOB_ID: + return new FeedRefreshTask(); + case TaskIds.COMPONENT_UPDATE_JOB_ID: + return new UpdateTask(); + case TaskIds.DEPRECATED_EXPLORE_SITES_REFRESH_JOB_ID: + case TaskIds.EXPLORE_SITES_REFRESH_JOB_ID: + return new ExploreSitesBackgroundTask(); + case TaskIds.BACKGROUND_SYNC_ONE_SHOT_JOB_ID: + return new BackgroundSyncBackgroundTask(); + case TaskIds.NOTIFICATION_SCHEDULER_JOB_ID: + return new NotificationSchedulerTask(); + case TaskIds.NOTIFICATION_TRIGGER_JOB_ID: + return new NotificationTriggerBackgroundTask(); + case TaskIds.PERIODIC_BACKGROUND_SYNC_CHROME_WAKEUP_TASK_JOB_ID: + return new PeriodicBackgroundSyncChromeWakeUpTask(); + // When adding a new job id with a BackgroundTask, remember to add a specific case for + // it here. + default: + Log.w(TAG, "Unable to find BackgroundTask class for task id " + taskId); + return null; + } + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java index 3130563..fca83375 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandler.java
@@ -11,13 +11,18 @@ import android.net.Uri; import android.text.TextUtils; +import org.chromium.base.BuildInfo; import org.chromium.base.ContextUtils; +import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.DeviceConditions; import org.chromium.chrome.browser.notifications.NotificationConstants; import org.chromium.chrome.browser.notifications.NotificationUmaTracker; import org.chromium.chrome.browser.notifications.PendingIntentProvider; import org.chromium.chrome.browser.sharing.SharingNotificationUtil; +import org.chromium.chrome.browser.util.IntentUtils; /** * Manages ClickToCall related notifications for Android. @@ -26,33 +31,40 @@ private static final String EXTRA_PHONE_NUMBER = "ClickToCallMessageHandler.EXTRA_PHONE_NUMBER"; /** + * Opens the dialer with the |phoneNumber| already prefilled. + * + * @param phoneNumber The phone number to show in the dialer. + */ + private static void openDialer(String phoneNumber) { + final Intent dialIntent; + if (!TextUtils.isEmpty(phoneNumber)) { + dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)); + } else { + dialIntent = new Intent(Intent.ACTION_DIAL); + } + dialIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + ContextUtils.getApplicationContext().startActivity(dialIntent); + ClickToCallUma.recordDialerShown(TextUtils.isEmpty(phoneNumber)); + } + + /** * Handles the tapping of a notification by opening the dialer with the * phone number specified in the notification. */ public static final class TapReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - String phoneNumber = intent.getStringExtra(EXTRA_PHONE_NUMBER); - final Intent dialIntent; - if (!TextUtils.isEmpty(phoneNumber)) { - dialIntent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:" + phoneNumber)); - } else { - dialIntent = new Intent(Intent.ACTION_DIAL); - } - dialIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - context.startActivity(dialIntent); - ClickToCallUma.recordDialerShown(TextUtils.isEmpty(phoneNumber)); + openDialer(IntentUtils.safeGetStringExtra(intent, EXTRA_PHONE_NUMBER)); } } /** - * Displays a notification that starts a phone call when clicked. + * Displays a notification that opens the dialer when clicked. * - * @param phoneNumber The phone number to call when the user taps on the notification. + * @param phoneNumber The phone number to show in the dialer when the user taps the + * notification. */ - @CalledByNative - private static void showNotification(String phoneNumber) { - ClickToCallUma.recordMessageReceived(); + private static void displayNotification(String phoneNumber) { Context context = ContextUtils.getApplicationContext(); PendingIntentProvider contentIntent = PendingIntentProvider.getBroadcast(context, /*requestCode=*/0, @@ -65,4 +77,34 @@ context.getResources().getString(R.string.click_to_call_notification_text), R.drawable.ic_phone_googblue_36dp); } + + /** + * Returns true if we should open the dialer straight away, and false if we should display a + * notification to click on instead. + */ + private static boolean shouldOpenDialer() { + // On Q and above, we could only open the dialer if we're in foreground, which would be an + // inconsistent experience. We always show the notification for those versions for now. + // Only show the dialer if the user would see it, otherwise show a notification. + return !BuildInfo.isAtLeastQ() + && ChromeFeatureList.isEnabled(ChromeFeatureList.CLICK_TO_CALL_OPEN_DIALER_DIRECTLY) + && DeviceConditions.isCurrentlyScreenOnAndUnlocked( + ContextUtils.getApplicationContext()); + } + + /** + * Handles a phone number sent from another device. + * + * @param phoneNumber The phone number to call. + */ + @CalledByNative + @VisibleForTesting + static void handleMessage(String phoneNumber) { + ClickToCallUma.recordMessageReceived(); + if (shouldOpenDialer()) { + openDialer(phoneNumber); + } else { + displayNotification(phoneNumber); + } + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java index 75bfbab..0277302 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappInfo.java
@@ -55,7 +55,6 @@ } } - private boolean mIsInitialized; private String mId; private Icon mIcon; private Uri mUri; @@ -203,16 +202,11 @@ mIsIconGenerated = isIconGenerated; mIsIconAdaptive = isIconAdaptive; mForceNavigation = forceNavigation; - mIsInitialized = mUri != null; } protected WebappInfo() { } - public boolean isInitialized() { - return mIsInitialized; - } - public String id() { return mId; }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sharing/OWNERS b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/OWNERS new file mode 100644 index 0000000..9eddd18 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/OWNERS
@@ -0,0 +1,4 @@ +file://chrome/browser/sharing/OWNERS + +# COMPONENT: UI>Browser>Sharing +# OS: Android
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandlerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandlerTest.java new file mode 100644 index 0000000..a702574 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/sharing/click_to_call/ClickToCallMessageHandlerTest.java
@@ -0,0 +1,119 @@ +// 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.sharing.click_to_call; + +import static org.junit.Assert.assertEquals; +import static org.robolectric.Shadows.shadowOf; + +import android.app.NotificationManager; +import android.content.Context; +import android.os.Build; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowNotificationManager; +import org.robolectric.util.ReflectionHelpers; + +import org.chromium.base.test.BaseRobolectricTestRunner; +import org.chromium.base.test.util.Feature; +import org.chromium.chrome.browser.ChromeFeatureList; +import org.chromium.chrome.browser.DeviceConditions; +import org.chromium.chrome.browser.ShadowDeviceConditions; +import org.chromium.chrome.test.util.browser.Features; +import org.chromium.net.ConnectionType; + +/** + * Tests for ClickToCallMessageHandler that check how we handle Click to Call messages. We either + * display a notification or directly open the dialer. + */ +@RunWith(BaseRobolectricTestRunner.class) +@Config(manifest = Config.NONE, shadows = {ShadowDeviceConditions.class}) +public class ClickToCallMessageHandlerTest { + @Rule + public TestRule mProcessor = new Features.JUnitProcessor(); + + /** + * Disabling the flag to directly open the dialer should force us to display a notification. + */ + @Test + @Feature({"Browser", "Sharing", "ClickToCall"}) + @Features.DisableFeatures({ChromeFeatureList.CLICK_TO_CALL_OPEN_DIALER_DIRECTLY}) + public void testHandleMessage_disabledFlagShouldDisplayNotification() { + setAtLeastAndroidQ(false); + setIsScreenOnAndUnlocked(true); + + ClickToCallMessageHandler.handleMessage("18004444444"); + + assertEquals(1, getShadowNotificationManager().size()); + } + + /** + * Android Q+ should always display a notification to open the dialer. + */ + @Test + @Feature({"Browser", "Sharing", "ClickToCall"}) + @Features.EnableFeatures({ChromeFeatureList.CLICK_TO_CALL_OPEN_DIALER_DIRECTLY}) + public void testHandleMessage_androidQShouldDisplayNotification() { + setAtLeastAndroidQ(true); + setIsScreenOnAndUnlocked(true); + + ClickToCallMessageHandler.handleMessage("18004444444"); + + assertEquals(1, getShadowNotificationManager().size()); + } + + /** + * Locked or turned off screens should force us to display a notification. + */ + @Test + @Feature({"Browser", "Sharing", "ClickToCall"}) + @Features.EnableFeatures({ChromeFeatureList.CLICK_TO_CALL_OPEN_DIALER_DIRECTLY}) + public void testHandleMessage_lockedScreenShouldDisplayNotification() { + setAtLeastAndroidQ(false); + setIsScreenOnAndUnlocked(false); + + ClickToCallMessageHandler.handleMessage("18004444444"); + + assertEquals(1, getShadowNotificationManager().size()); + } + + /** + * If all requirements are met, we want to open the dialer directly instead of displaying a + * notification. + */ + @Test + @Feature({"Browser", "Sharing", "ClickToCall"}) + @Features.EnableFeatures({ChromeFeatureList.CLICK_TO_CALL_OPEN_DIALER_DIRECTLY}) + public void testHandleMessage_opensDialerDirectly() { + setAtLeastAndroidQ(false); + setIsScreenOnAndUnlocked(true); + + ClickToCallMessageHandler.handleMessage("18004444444"); + + assertEquals(0, getShadowNotificationManager().size()); + } + + private void setAtLeastAndroidQ(boolean atLeastAndroidQ) { + // TODO(knollr): update to Build.VERSION_CODES.Q once available. + int versionCode = atLeastAndroidQ ? 29 : Build.VERSION_CODES.P; + ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", versionCode); + } + + private void setIsScreenOnAndUnlocked(boolean isScreenOnAndUnlocked) { + DeviceConditions deviceConditions = new DeviceConditions(false /* POWER_CONNECTED */, + 75 /* BATTERY_LEVEL */, ConnectionType.CONNECTION_WIFI, false /* POWER_SAVE */, + false /* metered */, isScreenOnAndUnlocked); + ShadowDeviceConditions.setCurrentConditions(deviceConditions); + } + + private ShadowNotificationManager getShadowNotificationManager() { + return shadowOf((NotificationManager) RuntimeEnvironment.application.getSystemService( + Context.NOTIFICATION_SERVICE)); + } +}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 4176bea..d9859fad 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1861,6 +1861,10 @@ {"enable-bookmark-reorder", flag_descriptions::kReorderBookmarksName, flag_descriptions::kReorderBookmarksDescription, kOsAndroid, FEATURE_VALUE_TYPE(chrome::android::kReorderBookmarks)}, + {"request-unbuffered-dispatch", + flag_descriptions::kRequestUnbufferedDispatchName, + flag_descriptions::kRequestUnbufferedDispatchDescription, kOsAndroid, + FEATURE_VALUE_TYPE(features::kRequestUnbufferedDispatch)}, #endif // OS_ANDROID {"in-product-help-demo-mode-choice", flag_descriptions::kInProductHelpDemoModeChoiceName, @@ -3228,11 +3232,6 @@ flag_descriptions::kBuiltInModuleAllDescription, kOsAll, FEATURE_VALUE_TYPE(features::kBuiltInModuleAll)}, - {"enable-blink-gen-property-trees", - flag_descriptions::kEnableBlinkGenPropertyTreesName, - flag_descriptions::kEnableBlinkGenPropertyTreesDescription, kOsAll, - FEATURE_VALUE_TYPE(blink::features::kBlinkGenPropertyTrees)}, - {"enable-backdrop-filter", flag_descriptions::kEnableCSSBackdropFilterName, flag_descriptions::kEnableCSSBackdropFilterDescription, kOsAll, FEATURE_VALUE_TYPE(blink::features::kCSSBackdropFilter)}, @@ -3530,8 +3529,7 @@ #if defined(OS_CHROMEOS) {"enable-chromeos-account-manager", flag_descriptions::kEnableChromeOsAccountManagerName, - flag_descriptions::kEnableChromeOsAccountManagerDescription, - kOsCrOS | kExpireM77, + flag_descriptions::kEnableChromeOsAccountManagerDescription, kOsCrOS, FEATURE_VALUE_TYPE(chromeos::features::kAccountManager)}, #endif @@ -3652,6 +3650,11 @@ #endif // defined(OS_CHROMEOS) #if defined(OS_ANDROID) + {"click-to-call-open-dialer-directly", + flag_descriptions::kClickToCallOpenDialerDirectlyName, + flag_descriptions::kClickToCallOpenDialerDirectlyDescription, kOsAndroid, + FEATURE_VALUE_TYPE(chrome::android::kClickToCallOpenDialerDirectly)}, + {"click-to-call-receiver", flag_descriptions::kClickToCallReceiverName, flag_descriptions::kClickToCallReceiverDescription, kOsAndroid, FEATURE_VALUE_TYPE(kClickToCallReceiver)}, @@ -4355,6 +4358,11 @@ flag_descriptions::kDecodeLossyWebPImagesToYUVName, flag_descriptions::kDecodeLossyWebPImagesToYUVDescription, kOsAll, FEATURE_VALUE_TYPE(blink::features::kDecodeLossyWebPImagesToYUV)}, + + {"dns-over-https", flag_descriptions::kDnsOverHttpsName, + flag_descriptions::kDnsOverHttpsDescription, kOsAll, + FEATURE_VALUE_TYPE(features::kDnsOverHttps)}, + // NOTE: Adding a new flag requires adding a corresponding entry to enum // "LoginCustomFlags" in tools/metrics/histograms/enums.xml. See "Flag // Histograms" in tools/metrics/histograms/README.md (run the @@ -4420,6 +4428,12 @@ } #endif // OS_WIN + // TODO(crbug.com/988078): Make the DoH entry visible for non-enterprise + // users. + if (!strcmp("dns-over-https", entry.internal_name)) { + return true; + } + return false; }
diff --git a/chrome/browser/accessibility/caption_settings_dialog_win.cc b/chrome/browser/accessibility/caption_settings_dialog_win.cc index aef787a..acbbe51 100644 --- a/chrome/browser/accessibility/caption_settings_dialog_win.cc +++ b/chrome/browser/accessibility/caption_settings_dialog_win.cc
@@ -26,8 +26,9 @@ namespace captions { void CaptionSettingsDialog::ShowCaptionSettingsDialog() { - base::PostTaskWithTraits( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::PostTask( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(CaptionSettingsDialogCallback)); }
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc index 872eacb64..1394e35e 100644 --- a/chrome/browser/android/chrome_feature_list.cc +++ b/chrome/browser/android/chrome_feature_list.cc
@@ -112,6 +112,7 @@ &kDontAutoHideBrowserControls, &kChromeDuetLabeled, &kChromeSmartSelection, + &kClickToCallOpenDialerDirectly, &kCommandLineOnNonRooted, &kContactsPickerSelectAll, &kContentSuggestionsScrollToLoad, @@ -334,6 +335,9 @@ const base::Feature kChromeSmartSelection{"ChromeSmartSelection", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kClickToCallOpenDialerDirectly{ + "ClickToCallOpenDialerDirectly", base::FEATURE_DISABLED_BY_DEFAULT}; + const base::Feature kCommandLineOnNonRooted{"CommandLineOnNonRooted", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h index bad8998..cca68f13 100644 --- a/chrome/browser/android/chrome_feature_list.h +++ b/chrome/browser/android/chrome_feature_list.h
@@ -45,6 +45,7 @@ extern const base::Feature kDontAutoHideBrowserControls; extern const base::Feature kChromeDuetLabeled; extern const base::Feature kChromeSmartSelection; +extern const base::Feature kClickToCallOpenDialerDirectly; extern const base::Feature kCommandLineOnNonRooted; extern const base::Feature kContactsPickerSelectAll; extern const base::Feature kContentSuggestionsScrollToLoad;
diff --git a/chrome/browser/android/feedback/process_id_feedback_source.cc b/chrome/browser/android/feedback/process_id_feedback_source.cc index 20318bd..33cb256 100644 --- a/chrome/browser/android/feedback/process_id_feedback_source.cc +++ b/chrome/browser/android/feedback/process_id_feedback_source.cc
@@ -54,7 +54,7 @@ process_ids_[content::PROCESS_TYPE_RENDERER].push_back( host->GetProcess().Pid()); } - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&ProcessIdFeedbackSource::PrepareProcessIdsOnIOThread, this)); @@ -67,7 +67,7 @@ process_ids_[iter.GetData().process_type].push_back( iter.GetData().GetProcess().Handle()); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::UI}, base::BindOnce(&ProcessIdFeedbackSource::PrepareCompleted, this)); }
diff --git a/chrome/browser/android/omnibox/autocomplete_controller_android.cc b/chrome/browser/android/omnibox/autocomplete_controller_android.cc index b348ced9..4fbc096e 100644 --- a/chrome/browser/android/omnibox/autocomplete_controller_android.cc +++ b/chrome/browser/android/omnibox/autocomplete_controller_android.cc
@@ -268,6 +268,15 @@ autocomplete_controller_->result().match_at(selected_index); SuggestionAnswer::LogAnswerUsed(match.answer); + TemplateURLService* template_url_service = + TemplateURLServiceFactory::GetForProfile(profile_); + if (template_url_service && + template_url_service->IsSearchResultsPageFromDefaultSearchProvider( + match.destination_url)) { + UMA_HISTOGRAM_BOOLEAN("Omnibox.Search.OffTheRecord", + profile_->IsOffTheRecord()); + } + UMA_HISTOGRAM_BOOLEAN( "Omnibox.SuggestionUsed.RichEntity", match.type == AutocompleteMatchType::SEARCH_SUGGEST_ENTITY);
diff --git a/chrome/browser/android/provider/run_on_ui_thread_blocking.h b/chrome/browser/android/provider/run_on_ui_thread_blocking.h index b6c5173..9f773cbb 100644 --- a/chrome/browser/android/provider/run_on_ui_thread_blocking.h +++ b/chrome/browser/android/provider/run_on_ui_thread_blocking.h
@@ -24,7 +24,7 @@ base::WaitableEvent finished( base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&RunOnUIThreadBlocking::RunOnUIThread<Signature>, runnable, &finished));
diff --git a/chrome/browser/android/thumbnail/thumbnail_cache.cc b/chrome/browser/android/thumbnail/thumbnail_cache.cc index c44762f..9c173fb 100644 --- a/chrome/browser/android/thumbnail/thumbnail_cache.cc +++ b/chrome/browser/android/thumbnail/thumbnail_cache.cc
@@ -133,8 +133,8 @@ size_t write_queue_max_size, bool use_approximation_thumbnail, bool save_jpeg_thumbnails) - : file_sequenced_task_runner_( - base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})), + : file_sequenced_task_runner_(base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock()})), compression_queue_max_size_(compression_queue_max_size), write_queue_max_size_(write_queue_max_size), use_approximation_thumbnail_(use_approximation_thumbnail), @@ -431,11 +431,11 @@ base::Bind(&ThumbnailCache::WriteJpegThumbnailIfNecessary, weak_factory_.GetWeakPtr(), tab_id); - base::PostTaskWithTraits(FROM_HERE, - {base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::BindOnce(&ThumbnailCache::JpegProcessingTask, - bitmap, post_jpeg_compression_task)); + base::PostTask(FROM_HERE, + {base::ThreadPool(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&ThumbnailCache::JpegProcessingTask, bitmap, + post_jpeg_compression_task)); } void ThumbnailCache::CompressThumbnailIfNecessary( @@ -461,12 +461,11 @@ gfx::Size encoded_size = GetEncodedSize( raw_data_size, ui_resource_provider_->SupportsETC1NonPowerOfTwo()); - base::PostTaskWithTraits( - FROM_HERE, - {base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::BindOnce(&ThumbnailCache::CompressionTask, bitmap, encoded_size, - post_compression_task)); + base::PostTask(FROM_HERE, + {base::ThreadPool(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&ThumbnailCache::CompressionTask, bitmap, + encoded_size, post_compression_task)); if (save_jpeg_thumbnails_) { SaveAsJpeg(tab_id, bitmap); @@ -640,8 +639,7 @@ if (!success) base::DeleteFile(file_path, false); - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - post_write_task); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, post_write_task); } void ThumbnailCache::WriteJpegTask( @@ -666,8 +664,7 @@ if (!success) base::DeleteFile(file_path, false); - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - post_write_task); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, post_write_task); } void ThumbnailCache::PostWriteTask() { @@ -716,10 +713,9 @@ } } - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(post_compression_task, std::move(compressed_data), - content_size)); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(post_compression_task, + std::move(compressed_data), content_size)); } void ThumbnailCache::JpegProcessingTask( @@ -744,9 +740,8 @@ gfx::JPEGCodec::Encode(result_bitmap, kCompressionQuality, &data); DCHECK(result); - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(post_processing_task, std::move(data))); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(post_processing_task, std::move(data))); } void ThumbnailCache::PostCompressionTask( @@ -907,15 +902,14 @@ } if (decompress) { - base::PostTaskWithTraits( - FROM_HERE, {base::TaskPriority::USER_VISIBLE}, - base::BindOnce(post_read_task, std::move(compressed_data), scale, - content_size)); + base::PostTask(FROM_HERE, + {base::ThreadPool(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(post_read_task, std::move(compressed_data), + scale, content_size)); } else { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(post_read_task, std::move(compressed_data), scale, - content_size)); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(post_read_task, std::move(compressed_data), + scale, content_size)); } } @@ -1015,7 +1009,7 @@ } } - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(post_decompression_callback, success, raw_data_small)); }
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index 77e2c44..ffc67b06 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -769,10 +769,11 @@ // Record the path to the (browser) app bundle; this is used by the app mode // shim. if (base::mac::AmIBundled()) { - base::PostTaskWithTraits(FROM_HERE, - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, - base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - base::BindOnce(&RecordLastRunAppBundlePath)); + base::PostTask( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(&RecordLastRunAppBundlePath)); } // Makes "Services" menu items available.
diff --git a/chrome/browser/apps/app_service/app_icon_factory.cc b/chrome/browser/apps/app_service/app_icon_factory.cc index 3f7e9589..ca3f933 100644 --- a/chrome/browser/apps/app_service/app_icon_factory.cc +++ b/chrome/browser/apps/app_service/app_icon_factory.cc
@@ -14,6 +14,7 @@ #include "base/task/post_task.h" #include "base/task/task_traits.h" #include "base/threading/scoped_blocking_call.h" +#include "base/threading/thread_restrictions.h" #include "chrome/browser/apps/app_service/dip_px_util.h" #include "chrome/browser/extensions/chrome_app_icon.h" #include "chrome/browser/extensions/chrome_app_icon_loader.h" @@ -28,6 +29,7 @@ #include "extensions/grit/extensions_browser_resources.h" #include "services/data_decoder/public/cpp/decode_image.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/codec/png_codec.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia.h" @@ -84,6 +86,36 @@ return ReadFileAsCompressedData(path); } +// Encode the ImageSkia to the compressed PNG data with the image's 1.0f scale +// factor representation. Return the encoded PNG data. +// +// This function should not be called on the UI thread. +std::vector<uint8_t> EncodeImage(const gfx::ImageSkia image) { + base::ScopedBlockingCall scoped_blocking_call(FROM_HERE, + base::BlockingType::MAY_BLOCK); + + std::vector<uint8_t> image_data; + + const gfx::ImageSkiaRep& image_skia_rep = image.GetRepresentation(1.0f); + if (image_skia_rep.scale() != 1.0f) { + return image_data; + } + + const SkBitmap& bitmap = image_skia_rep.GetBitmap(); + if (bitmap.drawsNothing()) { + return image_data; + } + + base::AssertLongCPUWorkAllowed(); + constexpr bool discard_transparency = false; + bool success = gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, discard_transparency, + &image_data); + if (!success) { + return std::vector<uint8_t>(); + } + return image_data; +} + // Runs |callback| passing an IconValuePtr with a compressed image: a // std::vector<uint8_t>. // @@ -95,15 +127,6 @@ apps::IconEffects icon_effects, apps::mojom::Publisher::LoadIconCallback callback, std::vector<uint8_t> data) { - // TODO(crbug.com/826982): if icon_effects is non-zero, we should arguably - // decompress the image, apply the icon_effects, and recompress the - // post-processed image. - // - // Even if there are no icon_effects, we might also want to do this if the - // size_hint_in_dip doesn't match the compressed image's pixel size. This - // isn't trivial, though, as determining the compressed image's pixel size - // might involve a sandboxed decoder process. - if (!data.empty()) { apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); iv->icon_compression = apps::mojom::IconCompression::kCompressed; @@ -127,7 +150,6 @@ int size_hint_in_dip, int default_icon_resource, bool is_placeholder_icon, - apps::IconEffects icon_effects, apps::mojom::Publisher::LoadIconCallback callback) { // Load some component extensions' icons from statically compiled // resources (built into the Chrome binary), and other extensions' @@ -141,11 +163,9 @@ // compressed icons (i.e. PNG-formatted data), not uncompressed // (i.e. a gfx::ImageSkia). - const gfx::Size dip_size = gfx::Size(size_hint_in_dip, size_hint_in_dip); - float scale = - ui::GetScaleForScaleFactor(apps_util::GetPrimaryDisplayUIScaleFactor()); - int size_hint_in_px = gfx::ScaleToFlooredSize(dip_size, scale).width(); - + constexpr bool quantize_to_supported_scale_factor = true; + int size_hint_in_px = apps_util::ConvertDipToPx( + size_hint_in_dip, quantize_to_supported_scale_factor); extensions::ExtensionResource ext_resource = extensions::IconsInfo::GetIconResource(extension, size_hint_in_px, ExtensionIconSet::MATCH_BIGGER); @@ -163,7 +183,7 @@ resource_id); RunCallbackWithCompressedData( size_hint_in_dip, default_icon_resource, is_placeholder_icon, - icon_effects, std::move(callback), + apps::IconEffects::kNone, std::move(callback), std::vector<uint8_t>(data.begin(), data.end())); return; } @@ -174,69 +194,85 @@ FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, base::BindOnce(&CompressedDataFromResource, std::move(ext_resource)), base::BindOnce(&RunCallbackWithCompressedData, size_hint_in_dip, - default_icon_resource, is_placeholder_icon, icon_effects, - std::move(callback))); + default_icon_resource, is_placeholder_icon, + apps::IconEffects::kNone, std::move(callback))); } // Runs |callback| passing an IconValuePtr with an uncompressed image: an // ImageSkia. // // It will fall back to the |default_icon_resource| if the image is null. -void RunCallbackWithUncompressedImageSkia( - int size_hint_in_dip, - int default_icon_resource, - bool is_placeholder_icon, - apps::IconEffects icon_effects, - apps::mojom::Publisher::LoadIconCallback callback, - const gfx::ImageSkia image) { +void RunCallbackWithImageSkia(int size_hint_in_dip, + int default_icon_resource, + bool is_placeholder_icon, + apps::IconEffects icon_effects, + apps::mojom::IconCompression icon_compression, + apps::mojom::Publisher::LoadIconCallback callback, + const gfx::ImageSkia image) { if (!image.isNull()) { - apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); - iv->icon_compression = apps::mojom::IconCompression::kUncompressed; - iv->uncompressed = image; - iv->is_placeholder_icon = is_placeholder_icon; - if (icon_effects && !iv->uncompressed.isNull()) { - ApplyIconEffects(icon_effects, size_hint_in_dip, &iv->uncompressed); + gfx::ImageSkia processed_image = image; + + // Apply the icon effects on the uncompressed data. If the caller requests + // an uncompressed icon, return the uncompressed result; otherwise, encode + // the icon to a compressed icon, return the compressed result. + if (icon_effects) { + ApplyIconEffects(icon_effects, size_hint_in_dip, &processed_image); } - std::move(callback).Run(std::move(iv)); + + if (icon_compression == apps::mojom::IconCompression::kUncompressed) { + apps::mojom::IconValuePtr iv = apps::mojom::IconValue::New(); + iv->icon_compression = apps::mojom::IconCompression::kUncompressed; + iv->uncompressed = processed_image; + iv->is_placeholder_icon = is_placeholder_icon; + std::move(callback).Run(std::move(iv)); + return; + } + + processed_image.MakeThreadSafe(); + base::PostTaskWithTraitsAndReplyWithResult( + FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, + base::BindOnce(&EncodeImage, processed_image), + base::BindOnce(&RunCallbackWithCompressedData, size_hint_in_dip, + default_icon_resource, is_placeholder_icon, icon_effects, + std::move(callback))); return; } + if (default_icon_resource) { - LoadIconFromResource(apps::mojom::IconCompression::kUncompressed, - size_hint_in_dip, default_icon_resource, - is_placeholder_icon, icon_effects, - std::move(callback)); + LoadIconFromResource(icon_compression, size_hint_in_dip, + default_icon_resource, is_placeholder_icon, + icon_effects, std::move(callback)); return; } std::move(callback).Run(apps::mojom::IconValue::New()); } -// Runs |callback| passing an IconValuePtr with an uncompressed image: an -// Image. -void RunCallbackWithUncompressedImage( - int size_hint_in_dip, - int default_icon_resource, - bool is_placeholder_icon, - apps::IconEffects icon_effects, - apps::mojom::Publisher::LoadIconCallback callback, - const gfx::Image& image) { - RunCallbackWithUncompressedImageSkia( - size_hint_in_dip, default_icon_resource, is_placeholder_icon, - icon_effects, std::move(callback), image.AsImageSkia()); +// Given a gfx::Image |image|, runs |callback| passing image.AsImageSkia(). +void RunCallbackWithImage(int size_hint_in_dip, + int default_icon_resource, + bool is_placeholder_icon, + apps::IconEffects icon_effects, + apps::mojom::IconCompression icon_compression, + apps::mojom::Publisher::LoadIconCallback callback, + const gfx::Image& image) { + RunCallbackWithImageSkia(size_hint_in_dip, default_icon_resource, + is_placeholder_icon, icon_effects, icon_compression, + std::move(callback), image.AsImageSkia()); } // Runs |callback| passing an IconValuePtr with an uncompressed image: a // SkBitmap. -void RunCallbackWithUncompressedSkBitmap( - int size_hint_in_dip, - bool is_placeholder_icon, - apps::IconEffects icon_effects, - apps::mojom::Publisher::LoadIconCallback callback, - const SkBitmap& bitmap) { +void RunCallbackWithSkBitmap(int size_hint_in_dip, + bool is_placeholder_icon, + apps::IconEffects icon_effects, + apps::mojom::IconCompression icon_compression, + apps::mojom::Publisher::LoadIconCallback callback, + const SkBitmap& bitmap) { constexpr int default_icon_resource = 0; gfx::ImageSkia image = gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 0.0f)); - RunCallbackWithUncompressedImageSkia(size_hint_in_dip, default_icon_resource, - is_placeholder_icon, icon_effects, - std::move(callback), image); + RunCallbackWithImageSkia(size_hint_in_dip, default_icon_resource, + is_placeholder_icon, icon_effects, icon_compression, + std::move(callback), image); } // Runs |callback| after converting (in a separate sandboxed process) from a @@ -267,8 +303,9 @@ content::GetSystemConnector(), data, data_decoder::mojom::ImageCodec::DEFAULT, false, data_decoder::kDefaultMaxSizeInBytes, gfx::Size(), - base::BindOnce(&RunCallbackWithUncompressedSkBitmap, size_hint_in_dip, - is_placeholder_icon, icon_effects, std::move(callback))); + base::BindOnce(&RunCallbackWithSkBitmap, size_hint_in_dip, + is_placeholder_icon, icon_effects, icon_compression, + std::move(callback))); } } // namespace @@ -296,19 +333,25 @@ case apps::mojom::IconCompression::kUnknown: break; - case apps::mojom::IconCompression::kUncompressed: { + case apps::mojom::IconCompression::kUncompressed: + case apps::mojom::IconCompression::kCompressed: { + if (icon_compression == apps::mojom::IconCompression::kCompressed && + icon_effects == IconEffects::kNone) { + RunCallbackWithCompressedDataFromExtension( + extension, size_hint_in_dip, default_icon_resource, + is_placeholder_icon, std::move(callback)); + return; + } + + // If |icon_effects| are requested, we must always load the + // uncompressed image to apply the icon effects, and then re-encode the + // image if the compressed icon is requested. extensions::ImageLoader::Get(context)->LoadImageAtEveryScaleFactorAsync( extension, gfx::Size(size_hint_in_dip, size_hint_in_dip), - base::BindOnce(&RunCallbackWithUncompressedImage, size_hint_in_dip, + base::BindOnce(&RunCallbackWithImage, size_hint_in_dip, default_icon_resource, is_placeholder_icon, - icon_effects, std::move(callback))); - return; - } - - case apps::mojom::IconCompression::kCompressed: { - RunCallbackWithCompressedDataFromExtension( - extension, size_hint_in_dip, default_icon_resource, - is_placeholder_icon, icon_effects, std::move(callback)); + icon_effects, icon_compression, + std::move(callback))); return; } } @@ -366,29 +409,34 @@ case apps::mojom::IconCompression::kUnknown: break; - case apps::mojom::IconCompression::kUncompressed: { + case apps::mojom::IconCompression::kUncompressed: + case apps::mojom::IconCompression::kCompressed: { + if (icon_compression == apps::mojom::IconCompression::kCompressed && + icon_effects == IconEffects::kNone) { + base::StringPiece data = + ui::ResourceBundle::GetSharedInstance().GetRawDataResource( + resource_id); + RunCallbackWithCompressedData( + size_hint_in_dip, default_icon_resource, is_placeholder_icon, + icon_effects, std::move(callback), + std::vector<uint8_t>(data.begin(), data.end())); + return; + } + + // If |icon_effects| are requested, we must always load the + // uncompressed image to apply the icon effects, and then re-encode the + // image if the compressed icon is requested. gfx::ImageSkia* unscaled = ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed( resource_id); - RunCallbackWithUncompressedImageSkia( + RunCallbackWithImageSkia( size_hint_in_dip, default_icon_resource, is_placeholder_icon, - icon_effects, std::move(callback), + icon_effects, icon_compression, std::move(callback), gfx::ImageSkiaOperations::CreateResizedImage( *unscaled, skia::ImageOperations::RESIZE_BEST, gfx::Size(size_hint_in_dip, size_hint_in_dip))); return; } - - case apps::mojom::IconCompression::kCompressed: { - base::StringPiece data = - ui::ResourceBundle::GetSharedInstance().GetRawDataResource( - resource_id); - RunCallbackWithCompressedData( - size_hint_in_dip, default_icon_resource, is_placeholder_icon, - icon_effects, std::move(callback), - std::vector<uint8_t>(data.begin(), data.end())); - return; - } } }
diff --git a/chrome/browser/apps/app_service/app_icon_source.cc b/chrome/browser/apps/app_service/app_icon_source.cc index 1b9c873..3dac4fa 100644 --- a/chrome/browser/apps/app_service/app_icon_source.cc +++ b/chrome/browser/apps/app_service/app_icon_source.cc
@@ -78,7 +78,9 @@ LoadDefaultImage(callback); return; } - int size_in_dip = apps_util::ConvertPxToDip(size); + constexpr bool quantize_to_supported_scale_factor = false; + int size_in_dip = + apps_util::ConvertPxToDip(size, quantize_to_supported_scale_factor); apps::AppServiceProxy* app_service_proxy = apps::AppServiceProxyFactory::GetForProfile(profile_);
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc index 190a376..a00d900 100644 --- a/chrome/browser/apps/app_service/arc_apps.cc +++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -395,10 +395,12 @@ return; } AppConnectionHolder* app_connection_holder = prefs->app_connection_holder(); - for (auto& pending : pending_load_icon_calls_) { - std::move(pending).Run(app_connection_holder); + if (app_connection_holder && app_connection_holder->IsConnected()) { + for (auto& pending : pending_load_icon_calls_) { + std::move(pending).Run(app_connection_holder); + } + pending_load_icon_calls_.clear(); } - pending_load_icon_calls_.clear(); } void ArcApps::OnAppRegistered(const std::string& app_id, @@ -516,22 +518,23 @@ if (prefs) { std::unique_ptr<ArcAppListPrefs::AppInfo> app_info = prefs->GetApp(app_id); if (app_info) { + constexpr bool quantize_to_supported_scale_factor = false; base::OnceCallback<void(apps::ArcApps::AppConnectionHolder*)> pending = - base::BindOnce(&LoadIcon0, icon_compression, - apps_util::ConvertDipToPx(size_hint_in_dip), - app_info->package_name, app_info->activity, - app_info->icon_resource_id, std::move(callback)); + base::BindOnce( + &LoadIcon0, icon_compression, + apps_util::ConvertDipToPx(size_hint_in_dip, + quantize_to_supported_scale_factor), + app_info->package_name, app_info->activity, + app_info->icon_resource_id, std::move(callback)); AppConnectionHolder* app_connection_holder = prefs->app_connection_holder(); - if (app_connection_holder) { - if (app_connection_holder->IsConnected()) { - std::move(pending).Run(app_connection_holder); - } else { - pending_load_icon_calls_.push_back(std::move(pending)); - } - return; + if (app_connection_holder && app_connection_holder->IsConnected()) { + std::move(pending).Run(app_connection_holder); + } else { + pending_load_icon_calls_.push_back(std::move(pending)); } + return; } } @@ -544,7 +547,9 @@ IconEffects icon_effects, LoadIconCallback callback) { // Use overloaded Chrome icon for Play Store that is adapted to Chrome style. - int size_hint_in_px = apps_util::ConvertDipToPx(size_hint_in_dip); + constexpr bool quantize_to_supported_scale_factor = false; + int size_hint_in_px = apps_util::ConvertDipToPx( + size_hint_in_dip, quantize_to_supported_scale_factor); int resource_id = (size_hint_in_px <= 32) ? IDR_ARC_SUPPORT_ICON_32 : IDR_ARC_SUPPORT_ICON_192; constexpr bool is_placeholder_icon = false;
diff --git a/chrome/browser/apps/app_service/dip_px_util.cc b/chrome/browser/apps/app_service/dip_px_util.cc index cbc7adfa..aa65f0c 100644 --- a/chrome/browser/apps/app_service/dip_px_util.cc +++ b/chrome/browser/apps/app_service/dip_px_util.cc
@@ -4,12 +4,10 @@ #include "chrome/browser/apps/app_service/dip_px_util.h" -#include <cmath> - -#include "base/numerics/safe_conversions.h" #include "ui/base/layout.h" #include "ui/display/display.h" #include "ui/display/screen.h" +#include "ui/gfx/geometry/size.h" // TODO(crbug.com/826982): plumb through enough information to use one of // Screen::GetDisplayNearest{Window/View/Point}. That way in multi-monitor @@ -26,18 +24,30 @@ return screen->GetPrimaryDisplay().device_scale_factor(); } +int ConvertBetweenDipAndPx(int value, + bool quantize_to_supported_scale_factor, + bool invert) { + float scale = GetPrimaryDisplayScaleFactor(); + if (quantize_to_supported_scale_factor) { + scale = ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(scale)); + } + DCHECK_NE(0.0f, scale); + if (invert) { + scale = 1 / scale; + } + return gfx::ScaleToFlooredSize(gfx::Size(value, value), scale).width(); +} + } // namespace namespace apps_util { -int ConvertDipToPx(int dip) { - return base::saturated_cast<int>( - std::floor(static_cast<float>(dip) * GetPrimaryDisplayScaleFactor())); +int ConvertDipToPx(int dip, bool quantize_to_supported_scale_factor) { + return ConvertBetweenDipAndPx(dip, quantize_to_supported_scale_factor, false); } -int ConvertPxToDip(int px) { - return base::saturated_cast<int>( - std::floor(static_cast<float>(px) / GetPrimaryDisplayScaleFactor())); +int ConvertPxToDip(int px, bool quantize_to_supported_scale_factor) { + return ConvertBetweenDipAndPx(px, quantize_to_supported_scale_factor, true); } ui::ScaleFactor GetPrimaryDisplayUIScaleFactor() {
diff --git a/chrome/browser/apps/app_service/dip_px_util.h b/chrome/browser/apps/app_service/dip_px_util.h index 81d24a4..949a47a 100644 --- a/chrome/browser/apps/app_service/dip_px_util.h +++ b/chrome/browser/apps/app_service/dip_px_util.h
@@ -7,13 +7,17 @@ // Utility functions for converting between DIP (device independent pixels) and // PX (physical pixels). +// +// "Supported scale factor" means a ui::ScaleFactor enum value (representing +// one of a finite number of floating point values) returned by +// ui::GetSupportedScaleFactor, defined in ui/base/layout.h. #include "ui/base/resource/scale_factor.h" namespace apps_util { -int ConvertDipToPx(int dip); -int ConvertPxToDip(int px); +int ConvertDipToPx(int dip, bool quantize_to_supported_scale_factor); +int ConvertPxToDip(int px, bool quantize_to_supported_scale_factor); ui::ScaleFactor GetPrimaryDisplayUIScaleFactor(); } // namespace apps_util
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h index 8d82caa..cc194da 100644 --- a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h +++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id.h
@@ -46,11 +46,13 @@ // The traits of the task that retrieves the device id. // + // ThreadPool(): This should run on a background thread. // MayBlock(): Since this requires fetching disk. // TaskPriority: USER_VISIBLE. Though this might be conservative, depending // on how GetDeviceId() is used. static constexpr base::TaskTraits traits() { - return {base::MayBlock(), base::TaskPriority::USER_VISIBLE}; + return {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::USER_VISIBLE}; } };
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc index 1e7a6891..d0470b96 100644 --- a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc +++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_linux.cc
@@ -182,8 +182,8 @@ raw_device_id = mac_address + disk_id; } - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(callback, raw_device_id)); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, raw_device_id)); } } // namespace @@ -192,7 +192,7 @@ void DeviceId::GetRawDeviceId(const IdCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, traits(), base::BindOnce(&GetRawDeviceIdImpl, base::Bind(&DeviceId::IsValidMacAddress), callback));
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc index 0233da9..01ee860 100644 --- a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc +++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_mac.cc
@@ -224,8 +224,8 @@ if (!mac_address.empty() && !disk_id.empty()) { raw_device_id = mac_address + disk_id; } - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(callback, raw_device_id)); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, raw_device_id)); } } // namespace @@ -234,7 +234,7 @@ void DeviceId::GetRawDeviceId(const IdCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, traits(), base::Bind(&GetRawDeviceIdImpl, base::Bind(&DeviceId::IsValidMacAddress), callback));
diff --git a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc index 62f304d..e1f6e57 100644 --- a/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc +++ b/chrome/browser/apps/platform_apps/api/music_manager_private/device_id_win.cc
@@ -176,8 +176,8 @@ LOG(ERROR) << "Could not find appropriate MAC address."; } - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(callback, mac_address)); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(callback, mac_address)); } std::string GetRlzMachineId() { @@ -209,7 +209,7 @@ void DeviceId::GetRawDeviceId(const IdCallback& callback) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, traits(), base::Bind(&GetMacAddress, base::Bind(&DeviceId::IsValidMacAddress), base::Bind(&GetMacAddressCallback, callback)));
diff --git a/chrome/browser/apps/platform_apps/shortcut_manager.cc b/chrome/browser/apps/platform_apps/shortcut_manager.cc index 08c075e..bf82f7d 100644 --- a/chrome/browser/apps/platform_apps/shortcut_manager.cc +++ b/chrome/browser/apps/platform_apps/shortcut_manager.cc
@@ -167,7 +167,7 @@ if (last_version >= kCurrentAppShortcutsVersion) return; - base::PostDelayedTaskWithTraits( + base::PostDelayedTask( FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&AppShortcutManager::UpdateShortcutsForAllAppsNow, weak_ptr_factory_.GetWeakPtr()),
diff --git a/chrome/browser/background/background_mode_manager_win.cc b/chrome/browser/background/background_mode_manager_win.cc index f8d633f..2c6db1e 100644 --- a/chrome/browser/background/background_mode_manager_win.cc +++ b/chrome/browser/background/background_mode_manager_win.cc
@@ -53,7 +53,7 @@ scoped_refptr<base::SequencedTaskRunner> BackgroundModeManager::CreateTaskRunner() { - return base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + return base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); }
diff --git a/chrome/browser/bookmarks/bookmark_html_writer.h b/chrome/browser/bookmarks/bookmark_html_writer.h index 3365891..780681f 100644 --- a/chrome/browser/bookmarks/bookmark_html_writer.h +++ b/chrome/browser/bookmarks/bookmark_html_writer.h
@@ -99,8 +99,8 @@ content::NotificationRegistrar registrar_; scoped_refptr<base::SequencedTaskRunner> background_io_task_runner_ = - base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT}); DISALLOW_COPY_AND_ASSIGN(BookmarkFaviconFetcher); };
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc index e54ad07d1..016a7707 100644 --- a/chrome/browser/bookmarks/bookmark_model_factory.cc +++ b/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -70,11 +70,11 @@ new BookmarkModel(std::make_unique<ChromeBookmarkClient>( profile, ManagedBookmarkServiceFactory::GetForProfile(profile), BookmarkSyncServiceFactory::GetForProfile(profile))); - bookmark_model->Load(profile->GetPrefs(), profile->GetPath(), - StartupTaskRunnerServiceFactory::GetForProfile(profile) - ->GetBookmarkTaskRunner(), - base::CreateSingleThreadTaskRunnerWithTraits( - {content::BrowserThread::UI})); + bookmark_model->Load( + profile->GetPrefs(), profile->GetPath(), + StartupTaskRunnerServiceFactory::GetForProfile(profile) + ->GetBookmarkTaskRunner(), + base::CreateSingleThreadTaskRunner({content::BrowserThread::UI})); BookmarkUndoServiceFactory::GetForProfile(profile)->Start(bookmark_model); return bookmark_model;
diff --git a/chrome/browser/browser_switcher/browser_switcher_service_win.cc b/chrome/browser/browser_switcher/browser_switcher_service_win.cc index 1866d44..0ed7de5f 100644 --- a/chrome/browser/browser_switcher/browser_switcher_service_win.cc +++ b/chrome/browser/browser_switcher/browser_switcher_service_win.cc
@@ -144,8 +144,9 @@ BrowserSwitcherServiceWin::BrowserSwitcherServiceWin(Profile* profile) : BrowserSwitcherService(profile), - sequenced_task_runner_(base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + sequenced_task_runner_(base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN})), weak_ptr_factory_(this) { if (prefs().IsEnabled())
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc index 1e6e520d..e79f2bd 100644 --- a/chrome/browser/captive_portal/captive_portal_browsertest.cc +++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -755,7 +755,7 @@ if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { SetNumJobsToWaitForOnInterceptorThread(num_jobs); } else { - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::UI}, base::BindOnce( &CaptivePortalBrowserTest::SetNumJobsToWaitForOnInterceptorThread, @@ -774,10 +774,9 @@ int num_ongoing_jobs = static_cast<int>(ongoing_mock_requests_.size()); if (num_ongoing_jobs == num_jobs) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&CaptivePortalBrowserTest::QuitRunLoop, - base::Unretained(this))); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&CaptivePortalBrowserTest::QuitRunLoop, + base::Unretained(this))); return; } @@ -791,10 +790,9 @@ // WaitForJobs, so makes sure there has been a matching WaitForJobs call. void FailJobs(int expected_num_jobs) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&CaptivePortalBrowserTest::FailJobs, - base::Unretained(this), expected_num_jobs)); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&CaptivePortalBrowserTest::FailJobs, + base::Unretained(this), expected_num_jobs)); return; } @@ -812,7 +810,7 @@ void FailJobsWithCertError(int expected_num_jobs, const net::SSLInfo& ssl_info) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::UI}, base::BindOnce(&CaptivePortalBrowserTest::FailJobsWithCertError, base::Unretained(this), expected_num_jobs, ssl_info)); @@ -832,10 +830,9 @@ EXPECT_EQ(expected_num_jobs, static_cast<int>(ongoing_mock_requests_.size())); for (auto& job : ongoing_mock_requests_) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&CaptivePortalBrowserTest::CreateLoader, - base::Unretained(this), std::move(job))); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&CaptivePortalBrowserTest::CreateLoader, + base::Unretained(this), std::move(job))); } ongoing_mock_requests_.clear(); } @@ -854,10 +851,9 @@ // behaves just as in FailJobs. void AbandonJobs(int expected_num_jobs) { if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&CaptivePortalBrowserTest::AbandonJobs, - base::Unretained(this), expected_num_jobs)); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&CaptivePortalBrowserTest::AbandonJobs, + base::Unretained(this), expected_num_jobs)); return; } @@ -987,10 +983,9 @@ if (num_jobs_to_wait_for_ == static_cast<int>(ongoing_mock_requests_.size())) { num_jobs_to_wait_for_ = 0; - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&CaptivePortalBrowserTest::QuitRunLoop, - base::Unretained(this))); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&CaptivePortalBrowserTest::QuitRunLoop, + base::Unretained(this))); } } } else {
diff --git a/chrome/browser/certificate_manager_model.cc b/chrome/browser/certificate_manager_model.cc index c175586..20a0137 100644 --- a/chrome/browser/certificate_manager_model.cc +++ b/chrome/browser/certificate_manager_model.cc
@@ -498,7 +498,7 @@ certificate_provider_service->CreateCertificateProvider(); #endif - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&CertificateManagerModel::GetCertDBOnIOThread, std::move(params), browser_context->GetResourceContext(), @@ -700,7 +700,7 @@ #if defined(OS_CHROMEOS) is_tpm_available = crypto::IsTPMTokenEnabledForNSS(); #endif - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::UI}, base::BindOnce(&CertificateManagerModel::DidGetCertDBOnUIThread, std::move(params), observer, callback, cert_db,
diff --git a/chrome/browser/chrome_browser_field_trials_desktop.cc b/chrome/browser/chrome_browser_field_trials_desktop.cc index 99387040..4e471c3 100644 --- a/chrome/browser/chrome_browser_field_trials_desktop.cc +++ b/chrome/browser/chrome_browser_field_trials_desktop.cc
@@ -186,8 +186,8 @@ browser_watcher::kStabilityDebuggingFeature, browser_watcher::kInitFlushParam, false); if (should_flush) { - base::PostTaskWithTraits( - FROM_HERE, {base::MayBlock()}, + base::PostTask( + FROM_HERE, {base::ThreadPool(), base::MayBlock()}, base::BindOnce(&base::PersistentMemoryAllocator::Flush, base::Unretained(global_tracker->allocator()), true)); }
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 76cab0d..fe7633ae 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -102,7 +102,7 @@ #include "chrome/browser/tracing/navigation_tracing.h" #include "chrome/browser/tracing/trace_event_system_stats_monitor.h" #include "chrome/browser/translate/translate_service.h" -#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h" +#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h" #include "chrome/browser/ui/profile_error_dialog.h" #include "chrome/browser/ui/startup/bad_flags_prompt.h" #include "chrome/browser/ui/startup/startup_browser_creator.h" @@ -1221,7 +1221,7 @@ javascript_dialog_extensions_client::InstallClient(); #endif // BUILDFLAG(ENABLE_EXTENSIONS) - InstallChromeJavaScriptNativeDialogFactory(); + InstallChromeJavaScriptNativeAppModalDialogFactory(); } void ChromeBrowserMainParts::PostProfileInit() {
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc index 2df74dc..8773e35 100644 --- a/chrome/browser/chrome_browser_main_android.cc +++ b/chrome/browser/chrome_browser_main_android.cc
@@ -78,8 +78,9 @@ void ChromeBrowserMainPartsAndroid::PostBrowserStart() { ChromeBrowserMainParts::PostBrowserStart(); - base::PostDelayedTaskWithTraits( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::PostDelayedTask( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::BindOnce(&ReportSeccompSupport), base::TimeDelta::FromMinutes(1)); RegisterChromeJavaMojoInterfaces();
diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm index e930cce3..6c622cc 100644 --- a/chrome/browser/chrome_browser_main_mac.mm +++ b/chrome/browser/chrome_browser_main_mac.mm
@@ -65,9 +65,9 @@ } void EnsureMetadataNeverIndexFile(const base::FilePath& user_data_dir) { - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, base::BindOnce(&EnsureMetadataNeverIndexFileOnFileThread, user_data_dir)); }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc index c6b4990..c08b993c 100644 --- a/chrome/browser/chrome_content_browser_client.cc +++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1180,9 +1180,8 @@ // the IO thread. DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&SetApplicationLocaleOnIOThread, locale)); + base::PostTask(FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&SetApplicationLocaleOnIOThread, locale)); } std::unique_ptr<content::BrowserMainParts> @@ -2356,7 +2355,7 @@ // Record access to database for potential display in UI. // Only post the task if this is for a specific tab. if (!wc_getter.is_null()) { - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {BrowserThread::UI}, base::BindOnce(&TabSpecificContentSettings::ServiceWorkerAccessed, std::move(wc_getter), scope, !allow_javascript, @@ -3628,8 +3627,7 @@ base::Bind(&CacheStatsRecorder::Create, render_process_host->GetID())); scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner = - base::CreateSingleThreadTaskRunnerWithTraits( - {content::BrowserThread::UI}); + base::CreateSingleThreadTaskRunner({content::BrowserThread::UI}); registry->AddInterface( base::Bind(&rappor::RapporRecorderImpl::Create, g_browser_process->rappor_service()), @@ -3661,7 +3659,7 @@ base::Bind( &ChromeContentBrowserClient::GetSafeBrowsingUrlCheckerDelegate, base::Unretained(this), resource_context)), - base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO})); + base::CreateSingleThreadTaskRunner({BrowserThread::IO})); } #endif @@ -3697,7 +3695,7 @@ registry->AddInterface( base::BindRepeating(&android::AvailableOfflineContentProvider::Create, profile), - base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI})); + base::CreateSingleThreadTaskRunner({BrowserThread::UI})); #endif for (auto* ep : extra_parts_) { @@ -4363,7 +4361,7 @@ #if defined(OS_ANDROID) frame_interfaces_parameterized_->AddInterface( base::BindRepeating(&offline_pages::OfflinePageAutoFetcher::Create), - base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI})); + base::CreateSingleThreadTaskRunner({BrowserThread::UI})); #endif } @@ -4497,7 +4495,7 @@ chrome_navigation_ui_data->prerender_mode(), chrome_navigation_ui_data->prerender_histogram_prefix(), base::BindOnce(GetPrerenderCanceller, wc_getter), - base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI}))); + base::CreateSingleThreadTaskRunner({BrowserThread::UI}))); } bool is_off_the_record = profile->IsOffTheRecord(); @@ -5023,9 +5021,9 @@ return false; #endif // defined(ANDROID) - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(&LaunchURL, url, web_contents_getter, - page_transition, has_user_gesture)); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(&LaunchURL, url, web_contents_getter, + page_transition, has_user_gesture)); return true; }
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc index 5571690..9e3cc31 100644 --- a/chrome/browser/chrome_service_worker_browsertest.cc +++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -237,7 +237,7 @@ msg.owned_encoded_message = blink::EncodeStringMessage(message_data); msg.encoded_message = msg.owned_encoded_message; - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::IO}, base::BindOnce( &content::ServiceWorkerContext::StartServiceWorkerAndDispatchMessage, @@ -262,7 +262,7 @@ msg.owned_encoded_message = blink::EncodeStringMessage(message_data); msg.encoded_message = msg.owned_encoded_message; - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(&content::ServiceWorkerContext:: StartServiceWorkerAndDispatchLongRunningMessage,
diff --git a/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl.cc b/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl.cc index 25b2396..e2f0bac 100644 --- a/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl.cc +++ b/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl.cc
@@ -119,6 +119,7 @@ EmptyAccountId(), // Not used. std::string(), // Not used. false, // Do not force a new key to be generated. + std::string(), // Leave key name empty to generate a default name. base::BindRepeating( [](const base::RepeatingCallback<void(const std::string&)> on_success, const base::RepeatingCallback<void(AttestationStatus)> on_failure,
diff --git a/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl_unittest.cc b/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl_unittest.cc index b56723a9..3a40919 100644 --- a/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl_unittest.cc +++ b/chrome/browser/chromeos/attestation/enrollment_certificate_uploader_impl_unittest.cc
@@ -80,8 +80,8 @@ // Setup expected cert generations. Again use WillOnce(). Cert generation // is another costly operation and if it gets triggered more than once // during a single pass this indicates a logical problem in the uploader. - EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _)) - .WillOnce(WithArgs<4>(Invoke(CertCallbackSuccess))); + EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .WillOnce(WithArgs<5>(Invoke(CertCallbackSuccess))); } void Run(bool expected_status) { @@ -111,14 +111,14 @@ } TEST_F(EnrollmentCertificateUploaderTest, GetCertificateUnspecifiedFailure) { - EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _)) - .WillRepeatedly(WithArgs<4>(Invoke(CertCallbackUnspecifiedFailure))); + EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .WillRepeatedly(WithArgs<5>(Invoke(CertCallbackUnspecifiedFailure))); Run(false /* expected_status */); } TEST_F(EnrollmentCertificateUploaderTest, GetCertificateBadRequestFailure) { - EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _)) - .WillOnce(WithArgs<4>(Invoke(CertCallbackBadRequestFailure))); + EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .WillOnce(WithArgs<5>(Invoke(CertCallbackBadRequestFailure))); Run(false /* expected_status */); }
diff --git a/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc index 44fe172..6bcd38e9 100644 --- a/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc +++ b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl.cc
@@ -204,6 +204,7 @@ EmptyAccountId(), // Not used. std::string(), // Not used. true, // Force a new key to be generated. + std::string(), // Leave key name empty to generate a default name. base::BindRepeating( [](const base::RepeatingCallback<void(const std::string&)> on_success, const base::RepeatingCallback<void(AttestationStatus)> on_failure,
diff --git a/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc index fa48c71..7657341c 100644 --- a/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc +++ b/chrome/browser/chromeos/attestation/machine_certificate_uploader_impl_unittest.cc
@@ -110,8 +110,8 @@ // another costly operation and if it gets triggered more than once during // a single pass this indicates a logical problem in the observer. if (new_key) { - EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _)) - .WillOnce(WithArgs<4>(Invoke(CertCallbackSuccess))); + EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .WillOnce(WithArgs<5>(Invoke(CertCallbackSuccess))); } } @@ -149,14 +149,14 @@ } TEST_P(MachineCertificateUploaderTest, GetCertificateUnspecifiedFailure) { - EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _)) - .WillRepeatedly(WithArgs<4>(Invoke(CertCallbackUnspecifiedFailure))); + EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .WillRepeatedly(WithArgs<5>(Invoke(CertCallbackUnspecifiedFailure))); Run(); } TEST_P(MachineCertificateUploaderTest, GetCertificateBadRequestFailure) { - EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _)) - .WillOnce(WithArgs<4>(Invoke(CertCallbackBadRequestFailure))); + EXPECT_CALL(attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .WillOnce(WithArgs<5>(Invoke(CertCallbackBadRequestFailure))); Run(); }
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc index 285c842..74275c5e 100644 --- a/chrome/browser/chromeos/attestation/platform_verification_flow.cc +++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc
@@ -265,9 +265,9 @@ AttestationFlow::CertificateCallback certificate_callback = base::Bind(&PlatformVerificationFlow::OnCertificateReady, this, context, account_id, base::Passed(&timer)); - attestation_flow_->GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE, - account_id, context.service_id, - force_new_key, certificate_callback); + attestation_flow_->GetCertificate( + PROFILE_CONTENT_PROTECTION_CERTIFICATE, account_id, context.service_id, + force_new_key, std::string() /*key_name*/, certificate_callback); } void PlatformVerificationFlow::OnCertificateReady( @@ -341,10 +341,12 @@ AttestationFlow::CertificateCallback renew_callback = base::Bind(&PlatformVerificationFlow::RenewCertificateCallback, this, certificate_chain); - attestation_flow_->GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE, - account_id, context.service_id, - true, // force_new_key - renew_callback); + attestation_flow_->GetCertificate( + PROFILE_CONTENT_PROTECTION_CERTIFICATE, account_id, context.service_id, + true, // force_new_key + std::string(), // key_name, empty means a default one will be + // generated. + renew_callback); } }
diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc index 6b47a22..82913cb 100644 --- a/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc +++ b/chrome/browser/chromeos/attestation/platform_verification_flow_unittest.cc
@@ -128,8 +128,8 @@ // Configure the mock AttestationFlow to call FakeGetCertificate. EXPECT_CALL(mock_attestation_flow_, GetCertificate(PROFILE_CONTENT_PROTECTION_CERTIFICATE, - account_id, kTestID, _, _)) - .WillRepeatedly(WithArgs<4>( + account_id, kTestID, _, _, _)) + .WillRepeatedly(WithArgs<5>( Invoke(this, &PlatformVerificationFlowTest::FakeGetCertificate))); // Configure the mock AsyncMethodCaller to call FakeSignChallenge.
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc b/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc index 593a1c6..2ad4d93 100644 --- a/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc +++ b/chrome/browser/chromeos/crostini/crostini_export_import_notification.cc
@@ -140,11 +140,7 @@ type_ == ExportImportType::EXPORT ? IDS_CROSTINI_EXPORT_NOTIFICATION_MESSAGE_DONE : IDS_CROSTINI_IMPORT_NOTIFICATION_MESSAGE_DONE)); - notification_->set_buttons( - type_ == ExportImportType::EXPORT - ? std::vector<message_center::ButtonInfo>{message_center::ButtonInfo( - l10n_util::GetStringUTF16(IDS_DOWNLOAD_LINK_SHOW))} - : std::vector<message_center::ButtonInfo>{}); + notification_->set_buttons({}); notification_->set_never_timeout(false); ForceRedisplay(); @@ -155,17 +151,8 @@ status_ = Status::CANCELLED; - notification_->set_type(message_center::NOTIFICATION_TYPE_SIMPLE); - notification_->set_accent_color(ash::kSystemNotificationColorNormal); - notification_->set_title(l10n_util::GetStringUTF16( - type_ == ExportImportType::EXPORT - ? IDS_CROSTINI_EXPORT_NOTIFICATION_TITLE_CANCELLED - : IDS_CROSTINI_IMPORT_NOTIFICATION_TITLE_CANCELLED)); - notification_->set_message({}); - notification_->set_buttons({}); - notification_->set_never_timeout(false); - - ForceRedisplay(); + NotificationDisplayService::GetForProfile(profile_)->Close( + NotificationHandler::Type::TRANSIENT, notification_->id()); } void CrostiniExportImportNotification::SetStatusFailed() { @@ -238,26 +225,22 @@ void CrostiniExportImportNotification::Click( const base::Optional<int>& button_index, const base::Optional<base::string16>&) { - if (!button_index) { - return; - } - switch (status_) { case Status::RUNNING: - DCHECK(*button_index == 1); - CrostiniExportImport::GetForProfile(profile_)->CancelOperation( - type_, container_id_); + if (button_index) { + DCHECK(*button_index == 1); + CrostiniExportImport::GetForProfile(profile_)->CancelOperation( + type_, container_id_); + } return; case Status::DONE: + DCHECK(!button_index); if (type_ == ExportImportType::EXPORT) { - DCHECK(*button_index == 1); platform_util::ShowItemInFolder(profile_, path_); - } else { - NOTREACHED(); } return; default: - NOTREACHED(); + DCHECK(!button_index); } }
diff --git a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc index 839141d..fab4ebb 100644 --- a/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc +++ b/chrome/browser/chromeos/crostini/crostini_export_import_unittest.cc
@@ -289,8 +289,8 @@ // CANCELLED: SendExportProgress( vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_CANCELLED); - EXPECT_EQ(notification->status(), - CrostiniExportImportNotification::Status::CANCELLED); + EXPECT_FALSE( + crostini_export_import_->GetNotificationForTesting(container_id_)); thread_bundle_.RunUntilIdle(); EXPECT_FALSE(base::PathExists(tarball_)); } @@ -317,8 +317,8 @@ // DONE: Completed before cancel processed, file should be deleted. SendExportProgress( vm_tools::cicerone::ExportLxdContainerProgressSignal_Status_DONE); - EXPECT_EQ(notification->status(), - CrostiniExportImportNotification::Status::CANCELLED); + EXPECT_FALSE( + crostini_export_import_->GetNotificationForTesting(container_id_)); thread_bundle_.RunUntilIdle(); EXPECT_FALSE(base::PathExists(tarball_)); } @@ -416,8 +416,8 @@ // CANCELLED: SendImportProgress( vm_tools::cicerone::ImportLxdContainerProgressSignal_Status_CANCELLED); - EXPECT_EQ(notification->status(), - CrostiniExportImportNotification::Status::CANCELLED); + EXPECT_FALSE( + crostini_export_import_->GetNotificationForTesting(container_id_)); } TEST_F(CrostiniExportImportTest, TestImportDoneBeforeCancelled) {
diff --git a/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc b/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc index 9c71e0c..a43b421 100644 --- a/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc +++ b/chrome/browser/chromeos/dbus/plugin_vm_service_provider.cc
@@ -81,7 +81,7 @@ // Validate subpage path. if ((request.subpage_path() != chrome::kPluginVmDetailsSubPage) && - (request.subpage_path() != chrome::kPluginVmSharedPathSubPage)) { + (request.subpage_path() != chrome::kPluginVmSharedPathsSubPage)) { constexpr char error_message[] = "Invalid subpage_path"; LOG(ERROR) << error_message; response_sender.Run(dbus::ErrorResponse::FromMethodCall(
diff --git a/chrome/browser/chromeos/input_method/ime_service_connector.cc b/chrome/browser/chromeos/input_method/ime_service_connector.cc index 2bd414a..6358737 100644 --- a/chrome/browser/chromeos/input_method/ime_service_connector.cc +++ b/chrome/browser/chromeos/input_method/ime_service_connector.cc
@@ -93,10 +93,10 @@ auto resource_request = std::make_unique<network::ResourceRequest>(); resource_request->url = url; - // Disable cookies for this request. resource_request->load_flags = - net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_BYPASS_CACHE | net::LOAD_DISABLE_CACHE; + // Disable cookies for this request. + resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request), traffic_annotation);
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc index e883195a..9b8efde 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -216,8 +216,8 @@ CreateAttestationFlow() { mock_ = new StrictMock<chromeos::attestation::MockAttestationFlow>(); if (ShouldRegisterWithCert()) { - EXPECT_CALL(*mock_, GetCertificate(_, _, _, _, _)) - .WillOnce(WithArgs<4>(Invoke(CertCallbackSuccess))); + EXPECT_CALL(*mock_, GetCertificate(_, _, _, _, _, _)) + .WillOnce(WithArgs<5>(Invoke(CertCallbackSuccess))); } return mock_; } @@ -876,7 +876,7 @@ EXPECT_CALL(*mock_, GetCertificate( chromeos::attestation::AttestationCertificateProfile:: PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, - _, _, _, _)) + _, _, _, _, _)) .Times(0); RunTest();
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc index 0066dbd..7348323 100644 --- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc +++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -457,7 +457,8 @@ weak_ptr_factory_.GetWeakPtr()); attestation_flow_->GetCertificate( chromeos::attestation::PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE, - EmptyAccountId(), "" /* request_origin */, false /* force_new_key */, + EmptyAccountId(), std::string() /* request_origin */, + false /* force_new_key */, std::string(), /* key_name */ callback); }
diff --git a/chrome/browser/devtools/device/adb/mock_adb_server.cc b/chrome/browser/devtools/device/adb/mock_adb_server.cc index 758309f..1a9f5bb 100644 --- a/chrome/browser/devtools/device/adb/mock_adb_server.cc +++ b/chrome/browser/devtools/device/adb/mock_adb_server.cc
@@ -625,7 +625,7 @@ void StartMockAdbServer(FlushMode flush_mode) { base::RunLoop run_loop; - base::PostTaskWithTraitsAndReply( + base::PostTaskAndReply( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&StartMockAdbServerOnIOThread, flush_mode), run_loop.QuitClosure()); @@ -634,8 +634,8 @@ void StopMockAdbServer() { base::RunLoop run_loop; - base::PostTaskWithTraitsAndReply(FROM_HERE, {BrowserThread::IO}, - base::BindOnce(&StopMockAdbServerOnIOThread), - run_loop.QuitClosure()); + base::PostTaskAndReply(FROM_HERE, {BrowserThread::IO}, + base::BindOnce(&StopMockAdbServerOnIOThread), + run_loop.QuitClosure()); run_loop.Run(); }
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc index 642ced71..6a906fd 100644 --- a/chrome/browser/devtools/device/android_device_manager.cc +++ b/chrome/browser/devtools/device/android_device_manager.cc
@@ -381,8 +381,8 @@ void OnCountDevices(const base::Callback<void(int)>& callback, int device_count) { - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(callback, device_count)); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(callback, device_count)); } } // namespace @@ -540,10 +540,10 @@ if (!thread_) return; // Shut down thread on a thread other than UI so it can join a thread. - base::PostTaskWithTraits( - FROM_HERE, - {base::WithBaseSyncPrimitives(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&HandlerThread::StopThread, thread_)); + base::PostTask(FROM_HERE, + {base::ThreadPool(), base::WithBaseSyncPrimitives(), + base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&HandlerThread::StopThread, thread_)); } // static
diff --git a/chrome/browser/devtools/device/cast_device_provider.cc b/chrome/browser/devtools/device/cast_device_provider.cc index e0a6bed..8cae795 100644 --- a/chrome/browser/devtools/device/cast_device_provider.cc +++ b/chrome/browser/devtools/device/cast_device_provider.cc
@@ -156,10 +156,9 @@ if (!lister_delegate_) { lister_delegate_.reset(new DeviceListerDelegate( weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get())); - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&DeviceListerDelegate::StartDiscovery, - lister_delegate_->AsWeakPtr())); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&DeviceListerDelegate::StartDiscovery, + lister_delegate_->AsWeakPtr())); } std::set<net::HostPortPair> targets; for (const auto& device_entry : device_info_map_)
diff --git a/chrome/browser/devtools/device/devtools_device_discovery.cc b/chrome/browser/devtools/device/devtools_device_discovery.cc index 101cddf5..b623a14 100644 --- a/chrome/browser/devtools/device/devtools_device_discovery.cc +++ b/chrome/browser/devtools/device/devtools_device_discovery.cc
@@ -46,9 +46,8 @@ const char kWebViewSocketPrefix[] = "webview_devtools_remote"; static void ScheduleTaskDefault(const base::Closure& task) { - base::PostDelayedTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, task, - base::TimeDelta::FromMilliseconds(kPollingIntervalMs)); + base::PostDelayedTask(FROM_HERE, {BrowserThread::UI}, task, + base::TimeDelta::FromMilliseconds(kPollingIntervalMs)); } // ProtocolCommand ------------------------------------------------------------
diff --git a/chrome/browser/devtools/device/port_forwarding_controller.cc b/chrome/browser/devtools/device/port_forwarding_controller.cc index be43c35..99fe24c6 100644 --- a/chrome/browser/devtools/device/port_forwarding_controller.cc +++ b/chrome/browser/devtools/device/port_forwarding_controller.cc
@@ -231,9 +231,9 @@ adb_thread_runner_(base::ThreadTaskRunnerHandle::Get()) { ResolveHostCallback resolve_host_callback = base::BindOnce( &SocketTunnel::OnResolveHostComplete, base::Unretained(this)); - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&ResolveHost, profile, host, port, - std::move(resolve_host_callback))); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&ResolveHost, profile, host, port, + std::move(resolve_host_callback))); } void OnResolveHostComplete(net::AddressList resolved_addresses) {
diff --git a/chrome/browser/devtools/device/tcp_device_provider.cc b/chrome/browser/devtools/device/tcp_device_provider.cc index 48a1ca31..49f340a 100644 --- a/chrome/browser/devtools/device/tcp_device_provider.cc +++ b/chrome/browser/devtools/device/tcp_device_provider.cc
@@ -157,10 +157,9 @@ } void TCPDeviceProvider::InitializeHostResolver() { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&TCPDeviceProvider::InitializeHostResolverOnUI, this, - mojo::MakeRequest(&host_resolver_))); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&TCPDeviceProvider::InitializeHostResolverOnUI, + this, mojo::MakeRequest(&host_resolver_))); host_resolver_.set_connection_error_handler(base::BindOnce( &TCPDeviceProvider::InitializeHostResolver, base::Unretained(this))); }
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc index 8da28af..36040c0 100644 --- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc +++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
@@ -518,7 +518,7 @@ void ScheduleDeviceCountRequest(const base::Closure& request) { DCHECK_CURRENTLY_ON(BrowserThread::UI); scheduler_invoked_++; - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, request); + base::PostTask(FROM_HERE, {BrowserThread::UI}, request); } virtual std::unique_ptr<FakeUsbDeviceManager> CreateFakeUsbManager() {
diff --git a/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc b/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc index 7888425..b5f1b12 100644 --- a/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc +++ b/chrome/browser/devtools/device/usb/usb_device_manager_helper.cc
@@ -200,7 +200,7 @@ base::BindOnce(&UsbDeviceManagerHelper::OnDeviceManagerConnectionError, weak_factory_.GetWeakPtr())); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&BindDeviceServiceOnUIThread, std::move(request))); }
diff --git a/chrome/browser/devtools/devtools_file_helper.cc b/chrome/browser/devtools/devtools_file_helper.cc index 546d65f..5c062c3 100644 --- a/chrome/browser/devtools/devtools_file_helper.cc +++ b/chrome/browser/devtools/devtools_file_helper.cc
@@ -217,8 +217,8 @@ : web_contents_(web_contents), profile_(profile), delegate_(delegate), - file_task_runner_( - base::CreateSequencedTaskRunnerWithTraits({base::MayBlock()})) { + file_task_runner_(base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock()})) { pref_change_registrar_.Init(profile_->GetPrefs()); }
diff --git a/chrome/browser/devtools/devtools_file_system_indexer.cc b/chrome/browser/devtools/devtools_file_system_indexer.cc index 96079b9..9e97b8e 100644 --- a/chrome/browser/devtools/devtools_file_system_indexer.cc +++ b/chrome/browser/devtools/devtools_file_system_indexer.cc
@@ -322,9 +322,8 @@ } if (file_path.empty()) { - base::PostTaskWithTraits( - FROM_HERE, {BrowserThread::UI}, - BindOnce(total_work_callback_, file_path_times_.size())); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + BindOnce(total_work_callback_, file_path_times_.size())); indexing_it_ = file_path_times_.begin(); IndexFiles(); return; @@ -360,7 +359,7 @@ return; if (indexing_it_ == file_path_times_.end()) { g_trigram_index.Get().NormalizeVectors(); - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, done_callback_); + base::PostTask(FROM_HERE, {BrowserThread::UI}, done_callback_); return; } FilePath file_path = indexing_it_->first; @@ -452,8 +451,8 @@ ++files_indexed_; if (should_send_worked_nitification) { last_worked_notification_time_ = current_time; - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - BindOnce(worked_callback_, files_indexed_)); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + BindOnce(worked_callback_, files_indexed_)); files_indexed_ = 0; } } @@ -516,6 +515,6 @@ if (path.IsParent(*it)) result.push_back(it->AsUTF8Unsafe()); } - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - BindOnce(callback, std::move(result))); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + BindOnce(callback, std::move(result))); }
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc index d81ee5ca..3aafea7 100644 --- a/chrome/browser/devtools/devtools_sanity_browsertest.cc +++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -621,7 +621,7 @@ if (host->GetType() == DevToolsAgentHost::kTypeSharedWorker && host->GetURL().path().rfind(path_) != std::string::npos) { *out_host_ = host; - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, quit_); + base::PostTask(FROM_HERE, {BrowserThread::UI}, quit_); delete this; } }
diff --git a/chrome/browser/devtools/protocol/browser_handler.cc b/chrome/browser/devtools/protocol/browser_handler.cc index 0dcf07c..371df6589 100644 --- a/chrome/browser/devtools/protocol/browser_handler.cc +++ b/chrome/browser/devtools/protocol/browser_handler.cc
@@ -111,9 +111,8 @@ } Response BrowserHandler::Close() { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce([]() { chrome::ExitIgnoreUnloadHandlers(); })); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce([]() { chrome::ExitIgnoreUnloadHandlers(); })); return Response::OK(); }
diff --git a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc index f0b2ed8..970f8db 100644 --- a/chrome/browser/dom_distiller/dom_distiller_service_factory.cc +++ b/chrome/browser/dom_distiller/dom_distiller_service_factory.cc
@@ -58,8 +58,8 @@ content::BrowserContext* context) const { Profile* profile = Profile::FromBrowserContext(context); scoped_refptr<base::SequencedTaskRunner> background_task_runner = - base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT}); base::FilePath database_dir( context->GetPath().Append(FILE_PATH_LITERAL("Articles")));
diff --git a/chrome/browser/downgrade/user_data_downgrade.cc b/chrome/browser/downgrade/user_data_downgrade.cc index c59e480..20023e0c 100644 --- a/chrome/browser/downgrade/user_data_downgrade.cc +++ b/chrome/browser/downgrade/user_data_downgrade.cc
@@ -152,8 +152,9 @@ base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir); content::BrowserThread::PostBestEffortTask( FROM_HERE, - base::CreateTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::CreateTaskRunner( + {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}), base::Bind(&DeleteMovedUserData, user_data_dir, GetDiskCacheDir())); }
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc index f6476d4d..f767c32 100644 --- a/chrome/browser/download/chrome_download_manager_delegate.cc +++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -325,8 +325,9 @@ next_download_id_(download::DownloadItem::kInvalidId), next_id_retrieved_(false), download_prefs_(new DownloadPrefs(profile)), - disk_access_task_runner_(base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + disk_access_task_runner_(base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})), is_file_picker_showing_(false) { #if defined(OS_ANDROID) @@ -532,8 +533,8 @@ download::DOWNLOAD_DANGER_TYPE_DANGEROUS_FILE, download::DOWNLOAD_INTERRUPT_REASON_NONE); } - base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI}, - internal_complete_callback); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + internal_complete_callback); return false; } } else if (!state->is_complete()) { @@ -1132,8 +1133,9 @@ const base::FilePath& path, const GetFileMimeTypeCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock()}, base::Bind(&GetMimeType, path), callback); + base::PostTaskAndReplyWithResult(FROM_HERE, + {base::ThreadPool(), base::MayBlock()}, + base::Bind(&GetMimeType, path), callback); } #if BUILDFLAG(FULL_SAFE_BROWSING)
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc index b61b2f1..bf8dbd3 100644 --- a/chrome/browser/download/download_commands.cc +++ b/chrome/browser/download/download_commands.cc
@@ -199,8 +199,8 @@ base::FilePath file_path = model_->GetFullPath(); if (!task_runner_) { - task_runner_ = base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + task_runner_ = base::CreateSequencedTaskRunner( + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); } ImageClipboardCopyManager::Start(file_path, task_runner_.get());
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc index 8dd55c4..a7243be 100644 --- a/chrome/browser/download/download_history.cc +++ b/chrome/browser/download/download_history.cc
@@ -517,10 +517,9 @@ // For database efficiency, batch removals together if they happen all at // once. if (removing_ids_.empty()) { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&DownloadHistory::RemoveDownloadsBatch, - weak_ptr_factory_.GetWeakPtr())); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&DownloadHistory::RemoveDownloadsBatch, + weak_ptr_factory_.GetWeakPtr())); } removing_ids_.insert(download_id); }
diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc index 0bc0250..af262a9 100644 --- a/chrome/browser/download/download_history_unittest.cc +++ b/chrome/browser/download/download_history_unittest.cc
@@ -55,10 +55,9 @@ void QueryDownloads( history::HistoryService::DownloadQueryCallback callback) override { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(&FakeHistoryAdapter::QueryDownloadsDone, - base::Unretained(this), std::move(callback))); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(&FakeHistoryAdapter::QueryDownloadsDone, + base::Unretained(this), std::move(callback))); } void QueryDownloadsDone(
diff --git a/chrome/browser/download/download_service_factory.cc b/chrome/browser/download/download_service_factory.cc index 5d9f825..471c3a9d 100644 --- a/chrome/browser/download/download_service_factory.cc +++ b/chrome/browser/download/download_service_factory.cc
@@ -154,8 +154,7 @@ auto blob_context_getter_factory = std::make_unique<DownloadBlobContextGetterFactory>(key); scoped_refptr<base::SingleThreadTaskRunner> io_task_runner = - base::CreateSingleThreadTaskRunnerWithTraits( - {content::BrowserThread::IO}); + base::CreateSingleThreadTaskRunner({content::BrowserThread::IO}); scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = SystemNetworkContextManager::GetInstance()->GetSharedURLLoaderFactory(); @@ -171,8 +170,8 @@ key->GetPath().Append(chrome::kDownloadServiceStorageDirname); } scoped_refptr<base::SequencedTaskRunner> background_task_runner = - base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT}); std::unique_ptr<download::TaskScheduler> task_scheduler; #if defined(OS_ANDROID)
diff --git a/chrome/browser/download/download_target_determiner.cc b/chrome/browser/download/download_target_determiner.cc index 1ebb1303..e61af07 100644 --- a/chrome/browser/download/download_target_determiner.cc +++ b/chrome/browser/download/download_target_determiner.cc
@@ -655,8 +655,8 @@ (plugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_IN_PROCESS || plugin_info.type == WebPluginInfo::PLUGIN_TYPE_PEPPER_OUT_OF_PROCESS || plugin_info.type == WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN); - base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, - base::BindOnce(callback, is_handled_safely)); + base::PostTask(FROM_HERE, {BrowserThread::UI}, + base::BindOnce(callback, is_handled_safely)); } } // namespace @@ -727,7 +727,8 @@ // IsAdobeReaderUpToDate() needs to be run with COM as it makes COM calls via // AssocQueryString() in IsAdobeReaderDefaultPDFViewer(). base::PostTaskAndReplyWithResult( - base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()}).get(), + base::CreateCOMSTATaskRunner({base::ThreadPool(), base::MayBlock()}) + .get(), FROM_HERE, base::Bind(&::IsAdobeReaderUpToDate), base::Bind(&DownloadTargetDeterminer::DetermineIfAdobeReaderUpToDateDone, weak_ptr_factory_.GetWeakPtr()));
diff --git a/chrome/browser/download/image_thumbnail_request.cc b/chrome/browser/download/image_thumbnail_request.cc index 037d69a..22e0b7fd 100644 --- a/chrome/browser/download/image_thumbnail_request.cc +++ b/chrome/browser/download/image_thumbnail_request.cc
@@ -79,8 +79,9 @@ void ImageThumbnailRequest::Start(const base::FilePath& path) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::PostTaskAndReplyWithResult( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(&LoadImageData, path), base::BindOnce(&ImageThumbnailRequest::OnLoadComplete, weak_ptr_factory_.GetWeakPtr())); @@ -111,8 +112,7 @@ void ImageThumbnailRequest::FinishRequest(SkBitmap thumbnail) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI}, - base::BindOnce(std::move(callback_), std::move(thumbnail))); + base::PostTask(FROM_HERE, {content::BrowserThread::UI}, + base::BindOnce(std::move(callback_), std::move(thumbnail))); delete this; }
diff --git a/chrome/browser/download/notification/download_item_notification.cc b/chrome/browser/download/notification/download_item_notification.cc index 451c0094..ef2dd55 100644 --- a/chrome/browser/download/notification/download_item_notification.cc +++ b/chrome/browser/download/notification/download_item_notification.cc
@@ -479,8 +479,10 @@ if (item_->HasSupportedImageMimeType()) { base::FilePath file_path = item_->GetFullPath(); - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::PostTaskAndReplyWithResult( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT}, base::Bind(&ReadNotificationImage, file_path), base::Bind(&DownloadItemNotification::OnImageLoaded, weak_factory_.GetWeakPtr())); @@ -530,8 +532,9 @@ return; } - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, + base::PostTaskAndReplyWithResult( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::Bind(&CropImage, decoded_bitmap), base::Bind(&DownloadItemNotification::OnImageCropped, weak_factory_.GetWeakPtr()));
diff --git a/chrome/browser/download/notification/download_notification_browsertest.cc b/chrome/browser/download/notification/download_notification_browsertest.cc index 9e8040f..369d9325 100644 --- a/chrome/browser/download/notification/download_notification_browsertest.cc +++ b/chrome/browser/download/notification/download_notification_browsertest.cc
@@ -280,7 +280,7 @@ if (!content::IsInProcessNetworkService()) { interceptor_ = std::make_unique<SlowDownloadInterceptor>(); } else { - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(&net::URLRequestSlowDownloadJob::AddUrlHandler)); }
diff --git a/chrome/browser/download/thumbnail_util.cc b/chrome/browser/download/thumbnail_util.cc index 5914ea7..da0304f 100644 --- a/chrome/browser/download/thumbnail_util.cc +++ b/chrome/browser/download/thumbnail_util.cc
@@ -41,8 +41,9 @@ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); // Scale down bitmap on another thread. - base::PostTaskWithTraitsAndReplyWithResult( - FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING}, + base::PostTaskAndReplyWithResult( + FROM_HERE, + {base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_BLOCKING}, base::BindOnce(&ScaleDownBitmapOnIOThread, icon_size, std::move(bitmap)), std::move(callback)); }
diff --git a/chrome/browser/engagement/important_sites_usage_counter.cc b/chrome/browser/engagement/important_sites_usage_counter.cc index dc33dbd..a1437d3 100644 --- a/chrome/browser/engagement/important_sites_usage_counter.cc +++ b/chrome/browser/engagement/important_sites_usage_counter.cc
@@ -45,7 +45,7 @@ void ImportantSitesUsageCounter::RunAndDestroySelfWhenFinished() { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); tasks_ += 1; - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::IO}, base::BindOnce(&ImportantSitesUsageCounter::GetQuotaUsageOnIOThread, base::Unretained(this))); @@ -65,7 +65,7 @@ void ImportantSitesUsageCounter::ReceiveQuotaUsageOnIOThread( std::vector<storage::UsageInfo> usage_infos) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - base::PostTaskWithTraits( + base::PostTask( FROM_HERE, {content::BrowserThread::UI}, base::BindOnce(&ImportantSitesUsageCounter::ReceiveQuotaUsage, base::Unretained(this), std::move(usage_infos)));
diff --git a/chrome/browser/engagement/important_sites_usage_counter_unittest.cc b/chrome/browser/engagement/important_sites_usage_counter_unittest.cc index 7294ff6..5f3b5ed 100644 --- a/chrome/browser/engagement/important_sites_usage_counter_unittest.cc +++ b/chrome/browser/engagement/important_sites_usage_counter_unittest.cc
@@ -45,8 +45,8 @@ QuotaManager* CreateQuotaManager() { quota_manager_ = new QuotaManager( false, temp_dir_.GetPath(), - base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}).get(), - nullptr, storage::GetQuotaSettingsFunc()); + base::CreateSingleThreadTaskRunner({BrowserThread::IO}).get(), nullptr, + storage::GetQuotaSettingsFunc()); return quota_manager_.get(); }
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc index 63d96eb..4d3b727b 100644 --- a/chrome/browser/engagement/site_engagement_service.cc +++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -188,10 +188,10 @@ SiteEngagementService::SiteEngagementService(Profile* profile) : SiteEngagementService(profile, base::DefaultClock::GetInstance()) { - base::PostTaskWithTraits( - FROM_HERE, {content::BrowserThread::UI, base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&SiteEngagementService::AfterStartupTask, - weak_factory_.GetWeakPtr())); + base::PostTask(FROM_HERE, + {content::BrowserThread::UI, base::TaskPriority::BEST_EFFORT}, + base::BindOnce(&SiteEngagementService::AfterStartupTask, + weak_factory_.GetWeakPtr())); if (!g_updated_from_variations) { SiteEngagementScore::UpdateFromVariations(kEngagementParams); @@ -479,9 +479,9 @@ // strong reference to HostContentSettingsMap (which supports outliving the // profile), and needs to avoid using any members of SiteEngagementService // (which does not). See https://crbug.com/900022. - base::PostTaskWithTraitsAndReplyWithResult( + base::PostTaskAndReplyWithResult( FROM_HERE, - {base::TaskPriority::BEST_EFFORT, + {base::ThreadPool(), base::TaskPriority::BEST_EFFORT, base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, base::BindOnce( &GetAllDetailsInBackground, clock_->Now(),
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc index 9e91c4b..60b2f63 100644 --- a/chrome/browser/engagement/site_engagement_service_unittest.cc +++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -225,7 +225,7 @@ const GURL& url) { double score = 0; base::RunLoop run_loop; - base::CreateSingleThreadTaskRunnerWithTraits({thread_id}) + base::CreateSingleThreadTaskRunner({thread_id}) ->PostTaskAndReply( FROM_HERE, base::BindOnce(&SiteEngagementServiceTest::CheckScoreFromSettings,
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc index ba3cd7e1..bffca7db 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc +++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
@@ -85,6 +85,7 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const cryptohome::AsyncMethodCaller::DataCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, true, "response")); @@ -98,6 +99,7 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const cryptohome::AsyncMethodCaller::DataCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, false, "")); @@ -108,6 +110,7 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const chromeos::attestation::AttestationFlow::CertificateCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -121,6 +124,7 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const chromeos::attestation::AttestationFlow::CertificateCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -141,9 +145,9 @@ ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _)) .WillByDefault(Invoke(RegisterKeyCallbackTrue)); ON_CALL(mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) .WillByDefault(Invoke(SignChallengeCallbackTrue)); - ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillByDefault(Invoke(GetCertificateCallbackTrue)); stub_install_attributes_.SetCloudManaged("google.com", "device_id"); @@ -297,7 +301,7 @@ } TEST_F(EPKChallengeMachineKeyTest, GetCertificateFailed) { - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillRepeatedly(Invoke(GetCertificateCallbackFalse)); EXPECT_EQ(GetCertificateError(kGetCertificateFailed), @@ -306,7 +310,7 @@ TEST_F(EPKChallengeMachineKeyTest, SignChallengeFailed) { EXPECT_CALL(mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) .WillRepeatedly(Invoke(SignChallengeCallbackFalse)); EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError, @@ -327,7 +331,8 @@ std::string()); // GetCertificate must not be called if the key exists. - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)).Times(0); + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .Times(0); EXPECT_TRUE(utils::RunFunction(func_.get(), CreateArgs(), browser(), extensions::api_test_utils::NONE)); @@ -354,14 +359,14 @@ EXPECT_CALL(mock_attestation_flow_, GetCertificate( chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, - _, _, _, _)) + _, _, _, _, _)) .Times(1); // SignEnterpriseChallenge must be called exactly once. - EXPECT_CALL( - mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge( - chromeos::attestation::KEY_DEVICE, cryptohome::Identification(), - "attest-ent-machine", "google.com", "device_id", _, "challenge", _)) + EXPECT_CALL(mock_async_method_caller_, + TpmAttestationSignEnterpriseChallenge( + chromeos::attestation::KEY_DEVICE, + cryptohome::Identification(), "attest-ent-machine", + "google.com", "device_id", _, "challenge", _, _)) .Times(1); std::unique_ptr<base::Value> value( @@ -373,24 +378,26 @@ } TEST_F(EPKChallengeMachineKeyTest, KeyRegisteredSuccess) { + std::string key_name_for_spkac = "attest-ent-machine-" + extension_->id(); // GetCertificate must be called exactly once. EXPECT_CALL(mock_attestation_flow_, GetCertificate( chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, - _, _, _, _)) + _, _, _, _, _)) .Times(1); // TpmAttestationRegisterKey must be called exactly once. EXPECT_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(chromeos::attestation::KEY_DEVICE, _ /* Unused by the API. */, - "attest-ent-machine", _)) + key_name_for_spkac, _)) .Times(1); // SignEnterpriseChallenge must be called exactly once. EXPECT_CALL( mock_async_method_caller_, TpmAttestationSignEnterpriseChallenge( chromeos::attestation::KEY_DEVICE, cryptohome::Identification(), - "attest-ent-machine", "google.com", "device_id", _, "challenge", _)) + "attest-ent-machine", "google.com", "device_id", _, "challenge", + key_name_for_spkac, _)) .Times(1); std::unique_ptr<base::Value> value(RunFunctionAndReturnSingleResult( @@ -488,7 +495,7 @@ } TEST_F(EPKChallengeUserKeyTest, GetCertificateFailed) { - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillRepeatedly(Invoke(GetCertificateCallbackFalse)); EXPECT_EQ(GetCertificateError(kGetCertificateFailed), @@ -497,7 +504,7 @@ TEST_F(EPKChallengeUserKeyTest, SignChallengeFailed) { EXPECT_CALL(mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) .WillRepeatedly(Invoke(SignChallengeCallbackFalse)); EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError, @@ -518,7 +525,8 @@ AccountId::FromUserEmail(kUserEmail)), "attest-ent-user", std::string()); // GetCertificate must not be called if the key exists. - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)).Times(0); + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) + .Times(0); EXPECT_TRUE(utils::RunFunction(func_.get(), CreateArgs(), browser(), extensions::api_test_utils::NONE)); @@ -545,7 +553,7 @@ EXPECT_CALL( mock_attestation_flow_, GetCertificate(chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE, - _, _, _, _)) + _, _, _, _, _)) .Times(1); const cryptohome::Identification cryptohome_id( AccountId::FromUserEmail(kUserEmail)); @@ -554,7 +562,7 @@ mock_async_method_caller_, TpmAttestationSignEnterpriseChallenge( chromeos::attestation::KEY_USER, cryptohome_id, "attest-ent-user", - kUserEmail, "device_id", _, "challenge", _)) + kUserEmail, "device_id", _, "challenge", _, _)) .Times(1); // RegisterKey must be called exactly once. EXPECT_CALL(mock_async_method_caller_,
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc index d46a285..c68aaa5 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc +++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.cc
@@ -43,6 +43,12 @@ #include "google_apis/gaia/gaia_auth_util.h" #include "third_party/cros_system_api/dbus/service_constants.h" +namespace { +// Prefix for naming machine keys used for SignedPublicKeyAndChallenge when +// challenging the EMK with register=true. +const char kEnterpriseMachineKeyForSpkacPrefix[] = "attest-ent-machine-"; +} // namespace + namespace extensions { namespace api_epkp = api::enterprise_platform_keys_private; @@ -68,12 +74,14 @@ const std::string& key_name, chromeos::attestation::AttestationCertificateProfile certificate_profile, bool require_user_consent, + const std::string& key_name_for_spkac, const base::Callback<void(PrepareKeyResult)>& callback) : key_type(key_type), account_id(account_id), key_name(key_name), certificate_profile(certificate_profile), require_user_consent(require_user_consent), + key_name_for_spkac(key_name_for_spkac), callback(callback) {} EPKPChallengeKeyBase::PrepareKeyContext::PrepareKeyContext( @@ -199,13 +207,11 @@ const std::string& key_name, chromeos::attestation::AttestationCertificateProfile certificate_profile, bool require_user_consent, + const std::string& key_name_for_spkac, const base::Callback<void(PrepareKeyResult)>& callback) { - const PrepareKeyContext context = PrepareKeyContext(key_type, - account_id, - key_name, - certificate_profile, - require_user_consent, - callback); + const PrepareKeyContext context = + PrepareKeyContext(key_type, account_id, key_name, certificate_profile, + require_user_consent, key_name_for_spkac, callback); cryptohome_client_->TpmAttestationIsPrepared( base::BindOnce(&EPKPChallengeKeyBase::IsAttestationPreparedCallback, base::Unretained(this), context)); @@ -224,6 +230,18 @@ base::Unretained(this), context)); return; } + + if (!context.key_name_for_spkac.empty()) { + // Generate a new key and have it signed by PCA. + attestation_flow_->GetCertificate( + context.certificate_profile, context.account_id, + std::string(), // Not used. + true, // Force a new key to be generated. + context.key_name_for_spkac, + base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, + base::Unretained(this), context.callback)); + return; + } // Attestation is available, see if the key we need already exists. cryptohome_client_->TpmAttestationDoesKeyExist( context.key_type, @@ -295,6 +313,7 @@ context.certificate_profile, context.account_id, std::string(), // Not used. true, // Force a new key to be generated. + std::string(), // Leave key name empty to generate a default name. base::Bind(&EPKPChallengeKeyBase::GetCertificateCallback, base::Unretained(this), context.callback)); } @@ -392,18 +411,31 @@ return; } + // The EMK cannot be registered as that would relinquish it and the DMServer + // relies on it to remain stable. If register_key = true, generate a new + // machine key to side-load into the system-wide token. This key will be + // used for SignedPublicKeyAndChallenge but the challenge response will still + // be singed using the stable EMK. + std::string key_name_for_spkac; + if (register_key) { + key_name_for_spkac = kEnterpriseMachineKeyForSpkacPrefix + extension_->id(); + } PrepareKey(chromeos::attestation::KEY_DEVICE, EmptyAccountId(), // Not used. chromeos::attestation::kEnterpriseMachineKey, chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, false, // user consent is not required. + key_name_for_spkac, base::Bind(&EPKPChallengeMachineKey::PrepareKeyCallback, - base::Unretained(this), challenge, register_key)); + base::Unretained(this), challenge, register_key, + key_name_for_spkac)); } -void EPKPChallengeMachineKey::PrepareKeyCallback(const std::string& challenge, - bool register_key, - PrepareKeyResult result) { +void EPKPChallengeMachineKey::PrepareKeyCallback( + const std::string& challenge, + bool register_key, + const std::string& key_name_for_spkac, + PrepareKeyResult result) { if (result != PREPARE_KEY_OK) { callback_.Run(false, base::StringPrintf(kGetCertificateFailedError, result)); @@ -418,7 +450,7 @@ GetDeviceId(), register_key ? chromeos::attestation::CHALLENGE_INCLUDE_SIGNED_PUBLIC_KEY : chromeos::attestation::CHALLENGE_OPTION_NONE, - challenge, + challenge, key_name_for_spkac, base::Bind(&EPKPChallengeMachineKey::SignChallengeCallback, base::Unretained(this), register_key)); } @@ -432,10 +464,12 @@ return; } if (register_key) { + std::string key_name_for_spkac = + kEnterpriseMachineKeyForSpkacPrefix + extension_->id(); async_caller_->TpmAttestationRegisterKey( chromeos::attestation::KEY_DEVICE, cryptohome::Identification(), // Not used. - chromeos::attestation::kEnterpriseMachineKey, + key_name_for_spkac, base::Bind(&EPKPChallengeMachineKey::RegisterKeyCallback, base::Unretained(this), response)); } else { @@ -559,7 +593,7 @@ PrepareKey(chromeos::attestation::KEY_USER, GetAccountId(), chromeos::attestation::kEnterpriseUserKey, chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE, - require_user_consent, + require_user_consent, std::string() /* key_name_for_spkac */, base::Bind(&EPKPChallengeUserKey::PrepareKeyCallback, base::Unretained(this), challenge, register_key)); } @@ -580,7 +614,7 @@ chromeos::attestation::kEnterpriseUserKey, GetUserEmail(), GetDeviceId(), register_key ? chromeos::attestation::CHALLENGE_INCLUDE_SIGNED_PUBLIC_KEY : chromeos::attestation::CHALLENGE_OPTION_NONE, - challenge, + challenge, std::string() /* key_name_for_spkac */, base::Bind(&EPKPChallengeUserKey::SignChallengeCallback, base::Unretained(this), register_key)); }
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h index 460ed7b..e8e9fa0 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h +++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api.h
@@ -100,16 +100,18 @@ // Returns the enterprise virtual device ID. std::string GetDeviceId() const; - // Prepares the key for signing. It will first check if the key exists. If - // the key does not exist, it will call AttestationFlow::GetCertificate() to - // get a new one. If require_user_consent is true, it will explicitly ask for - // user consent before calling GetCertificate(). + // Prepares the key for signing. It will first check if a new key should be + // generated, i.e. |key_name_for_spkac| is not empty or the key doesn't + // exist and, if necessary, call AttestationFlow::GetCertificate() to get a + // new one. If require_user_consent is true, it will explicitly ask for user + // consent before calling GetCertificate(). void PrepareKey( chromeos::attestation::AttestationKeyType key_type, const AccountId& account_id, const std::string& key_name, chromeos::attestation::AttestationCertificateProfile certificate_profile, bool require_user_consent, + const std::string& key_name_for_spkac, const base::Callback<void(PrepareKeyResult)>& callback); chromeos::CryptohomeClient* cryptohome_client_; @@ -130,6 +132,7 @@ chromeos::attestation::AttestationCertificateProfile certificate_profile, bool require_user_consent, + const std::string& key_name_for_spkac, const base::Callback<void(PrepareKeyResult)>& callback); PrepareKeyContext(const PrepareKeyContext& other); ~PrepareKeyContext(); @@ -139,6 +142,7 @@ const std::string key_name; chromeos::attestation::AttestationCertificateProfile certificate_profile; bool require_user_consent; + std::string key_name_for_spkac; const base::Callback<void(PrepareKeyResult)> callback; }; @@ -195,6 +199,7 @@ bool enabled); void PrepareKeyCallback(const std::string& challenge, bool register_key, + const std::string& key_name_for_spkac, PrepareKeyResult result); void SignChallengeCallback(bool register_key, bool success,
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc index 3dc0c29..6230610 100644 --- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc +++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -88,6 +88,7 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const cryptohome::AsyncMethodCaller::DataCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, true, "response")); @@ -101,6 +102,7 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const cryptohome::AsyncMethodCaller::DataCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(callback, false, "")); @@ -111,6 +113,7 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const chromeos::attestation::AttestationFlow::CertificateCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -124,6 +127,7 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const chromeos::attestation::AttestationFlow::CertificateCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -138,6 +142,7 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const chromeos::attestation::AttestationFlow::CertificateCallback& callback) { base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -164,9 +169,9 @@ ON_CALL(mock_async_method_caller_, TpmAttestationRegisterKey(_, _, _, _)) .WillByDefault(Invoke(RegisterKeyCallbackTrue)); ON_CALL(mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) .WillByDefault(Invoke(SignChallengeCallbackTrue)); - ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillByDefault(Invoke(GetCertificateCallbackTrue)); stub_install_attributes_.SetCloudManaged("google.com", "device_id"); @@ -301,7 +306,7 @@ } TEST_F(EPKPChallengeMachineKeyTest, GetCertificateFailed) { - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillRepeatedly(Invoke(GetCertificateCallbackUnspecifiedFailure)); EXPECT_EQ(GetCertificateError(kGetCertificateFailed), @@ -310,7 +315,7 @@ TEST_F(EPKPChallengeMachineKeyTest, SignChallengeFailed) { EXPECT_CALL(mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) .WillRepeatedly(Invoke(SignChallengeCallbackFalse)); EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError, @@ -321,7 +326,7 @@ cryptohome_client_.SetTpmAttestationDeviceCertificate("attest-ent-machine", std::string()); // GetCertificate must not be called if the key exists. - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .Times(0); EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), @@ -366,14 +371,14 @@ EXPECT_CALL(mock_attestation_flow_, GetCertificate( chromeos::attestation::PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, - _, _, _, _)) + _, _, _, _, _)) .Times(1); // SignEnterpriseChallenge must be called exactly once. - EXPECT_CALL( - mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge( - chromeos::attestation::KEY_DEVICE, cryptohome::Identification(), - "attest-ent-machine", "google.com", "device_id", _, "challenge", _)) + EXPECT_CALL(mock_async_method_caller_, + TpmAttestationSignEnterpriseChallenge( + chromeos::attestation::KEY_DEVICE, + cryptohome::Identification(), "attest-ent-machine", + "google.com", "device_id", _, "challenge", _, _)) .Times(1); std::unique_ptr<base::Value> value(utils::RunFunctionAndReturnSingleResult( @@ -464,7 +469,7 @@ } TEST_F(EPKPChallengeUserKeyTest, GetCertificateFailedWithUnspecifiedFailure) { - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillRepeatedly(Invoke(GetCertificateCallbackUnspecifiedFailure)); EXPECT_EQ(GetCertificateError(kGetCertificateFailed), @@ -472,7 +477,7 @@ } TEST_F(EPKPChallengeUserKeyTest, GetCertificateFailedWithBadRequestFailure) { - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .WillRepeatedly(Invoke(GetCertificateCallbackBadRequestFailure)); EXPECT_EQ(GetCertificateError(kGetCertificateFailed), @@ -481,7 +486,7 @@ TEST_F(EPKPChallengeUserKeyTest, SignChallengeFailed) { EXPECT_CALL(mock_async_method_caller_, - TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) .WillRepeatedly(Invoke(SignChallengeCallbackFalse)); EXPECT_EQ(EPKPChallengeKeyBase::kSignChallengeFailedError, @@ -502,7 +507,7 @@ AccountId::FromUserEmail(kUserEmail)), "attest-ent-user", std::string()); // GetCertificate must not be called if the key exists. - EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) + EXPECT_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _, _)) .Times(0); EXPECT_TRUE(utils::RunFunction(func_.get(), kArgs, browser(), @@ -527,10 +532,10 @@ TEST_F(EPKPChallengeUserKeyTest, Success) { // GetCertificate must be called exactly once. - EXPECT_CALL(mock_attestation_flow_, - GetCertificate( - chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE, - _, _, _, _)) + EXPECT_CALL( + mock_attestation_flow_, + GetCertificate(chromeos::attestation::PROFILE_ENTERPRISE_USER_CERTIFICATE, + _, _, _, _, _)) .Times(1); const AccountId account_id = AccountId::FromUserEmail(kUserEmail); // SignEnterpriseChallenge must be called exactly once. @@ -539,7 +544,7 @@ chromeos::attestation::KEY_USER, cryptohome::Identification(account_id), "attest-ent-user", cryptohome::Identification(account_id).id(), "device_id", _, - "challenge", _)) + "challenge", _, _)) .Times(1); // RegisterKey must be called exactly once. EXPECT_CALL(mock_async_method_caller_,
diff --git a/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc b/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc index 74e95cb0..2b6386c 100644 --- a/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc +++ b/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc
@@ -188,11 +188,13 @@ EXPECT_EQ(user_private_slot_db_.slot(), cert_db->GetPrivateSlot().get()); EXPECT_NE(cert_db->GetPrivateSlot().get(), cert_db->GetPublicSlot().get()); - auto* slot = user_client_cert_slot_ == UserClientCertSlot::kPrivateSlot - ? cert_db->GetPrivateSlot().get() - : cert_db->GetPublicSlot().get(); + crypto::ScopedPK11Slot slot = + user_client_cert_slot_ == UserClientCertSlot::kPrivateSlot + ? cert_db->GetPrivateSlot() + : cert_db->GetPublicSlot(); client_cert1_ = net::ImportClientCertAndKeyFromFile( - net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", slot); + net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8", + slot.get()); ASSERT_TRUE(client_cert1_.get()); // Import a second client cert signed by another CA than client_1 into the
diff --git a/chrome/browser/feature_engagement/tracker_factory.cc b/chrome/browser/feature_engagement/tracker_factory.cc index f341d74..f6f4aaff 100644 --- a/chrome/browser/feature_engagement/tracker_factory.cc +++ b/chrome/browser/feature_engagement/tracker_factory.cc
@@ -44,8 +44,8 @@ Profile* profile = Profile::FromBrowserContext(context); scoped_refptr<base::SequencedTaskRunner> background_task_runner = - base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); + base::CreateSequencedTaskRunner({base::ThreadPool(), base::MayBlock(), + base::TaskPriority::BEST_EFFORT}); base::FilePath storage_dir = profile->GetPath().Append( chrome::kFeatureEngagementTrackerStorageDirname);
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json index f780ee6..36725ba5 100644 --- a/chrome/browser/flag-metadata.json +++ b/chrome/browser/flag-metadata.json
@@ -398,6 +398,11 @@ "owners": [ "//chrome/browser/sharing/OWNERS" ], "expiry_milestone": 80 }, + { + "name": "click-to-call-open-dialer-directly", + "owners": [ "//chrome/browser/sharing/OWNERS" ], + "expiry_milestone": 81 + }, { "name": "click-to-call-receiver", "owners": [ "//chrome/browser/sharing/OWNERS" ], @@ -679,6 +684,11 @@ "expiry_milestone": 80 }, { + "name": "dns-over-https", + "owners": [ "dalyk", "doh-core@google.com" ], + "expiry_milestone": 81 + }, + { "name": "document-passive-event-listeners", "owners": [ "nzolghadr, input-dev" ], "expiry_milestone": 76 @@ -952,11 +962,6 @@ "expiry_milestone": 86 }, { - "name": "enable-blink-gen-property-trees", - "owners": [ "paint-dev@chromium.org" ], - "expiry_milestone": 74 - }, - { "name": "enable-bookmark-reorder", "owners": ["jhimawan@google.com", "twellington" ], "expiry_milestone": 80 @@ -999,7 +1004,7 @@ { "name": "enable-chromeos-account-manager", "owners": [ "sinhak@chromium.org" ], - "expiry_milestone": 78 + "expiry_milestone": 79 }, { "name": "enable-cloud-print-xps", @@ -2778,6 +2783,11 @@ "expiry_milestone": 79 }, { + "name": "request-unbuffered-dispatch", + "owners": [ "bokan" ], + "expiry_milestone": 80 + }, + { "name": "rewrite-leveldb-on-deletion", "owners": [ "dullweber" ], "expiry_milestone": 75
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 3301746..f451251 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -102,6 +102,12 @@ "Allow Chrome to offer to generate passwords when it detects account " "creation pages."; +const char kDnsOverHttpsName[] = "Secure DNS lookups"; +const char kDnsOverHttpsDescription[] = + "Enables DNS over HTTPS. When this feature is enabled, your browser may " + "try to use a secure HTTPS connection to look up the addresses of websites " + "and other web resources."; + const char kDrawVerticallyEdgeToEdgeName[] = "Draw contents vertically from edge to edge."; const char kDrawVerticallyEdgeToEdgeDescription[] = @@ -672,11 +678,6 @@ "Allows users to drag tabs between pinned and unpinned tabs to modify the " "pinned state of the tab."; -const char kEnableBlinkGenPropertyTreesName[] = "Enable BlinkGenPropertyTrees"; -const char kEnableBlinkGenPropertyTreesDescription[] = - "Enable a new compositing mode where Blink generates the compositor " - "property trees."; - const char kEnableCSSBackdropFilterName[] = "Enable backdrop-filter"; const char kEnableCSSBackdropFilterDescription[] = "Enable a new CSS property called backdrop-filter."; @@ -1595,6 +1596,11 @@ "Allows the user to reorder their bookmarks from their Android device. " "The bookmark ordering will be synced across devices."; +const char kRequestUnbufferedDispatchName[] = "Use RequestUnbufferedDispatch"; +const char kRequestUnbufferedDispatchDescription[] = + "Calls RequestUnbufferedDispatch in the Android API to disable buffering " + "of input by the OS."; + const char kRequestTabletSiteName[] = "Request tablet site option in the settings menu"; const char kRequestTabletSiteDescription[] = @@ -2255,6 +2261,12 @@ "Enables clearing of browsing data which is older than a given time " "period."; +const char kClickToCallOpenDialerDirectlyName[] = + "Open the dialer directly for Click to Call"; +const char kClickToCallOpenDialerDirectlyDescription[] = + "Enables opening the dialer directly instead of displaying a notification. " + "Only available on Android P- and when the screen is on and unlocked."; + const char kClickToCallReceiverName[] = "Enable receiver device to handle click to call feature"; const char kClickToCallReceiverDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 8ecfe4d..5b84a8e 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -174,6 +174,9 @@ extern const char kDecodeLossyWebPImagesToYUVName[]; extern const char kDecodeLossyWebPImagesToYUVDescription[]; +extern const char kDnsOverHttpsName[]; +extern const char kDnsOverHttpsDescription[]; + extern const char kDrawVerticallyEdgeToEdgeName[]; extern const char kDrawVerticallyEdgeToEdgeDescription[]; @@ -400,9 +403,6 @@ extern const char kBuiltInModuleKvStorageName[]; extern const char kBuiltInModuleKvStorageDescription[]; -extern const char kEnableBlinkGenPropertyTreesName[]; -extern const char kEnableBlinkGenPropertyTreesDescription[]; - extern const char kEnableCSSBackdropFilterName[]; extern const char kEnableCSSBackdropFilterDescription[]; @@ -958,6 +958,9 @@ extern const char kReorderBookmarksName[]; extern const char kReorderBookmarksDescription[]; +extern const char kRequestUnbufferedDispatchName[]; +extern const char kRequestUnbufferedDispatchDescription[]; + extern const char kRequestTabletSiteName[]; extern const char kRequestTabletSiteDescription[]; @@ -1339,6 +1342,9 @@ extern const char kClearOldBrowsingDataName[]; extern const char kClearOldBrowsingDataDescription[]; +extern const char kClickToCallOpenDialerDirectlyName[]; +extern const char kClickToCallOpenDialerDirectlyDescription[]; + extern const char kClickToCallReceiverName[]; extern const char kClickToCallReceiverDescription[];
diff --git a/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.cc b/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.cc index 35eb384..59c69f3 100644 --- a/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.cc +++ b/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.cc
@@ -109,8 +109,6 @@ observers_.end()); } -void OpenScreenListener::RunTasks() {} - void OpenScreenListener::OnDeviceChanged( const std::string& service_type, bool added,
diff --git a/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.h b/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.h index e8dd2abc..9cdb1be 100644 --- a/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.h +++ b/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.h
@@ -35,8 +35,6 @@ void AddObserver(ServiceListener::Observer* observer) override; void RemoveObserver(ServiceListener::Observer* observer) override; - void RunTasks() override; - // ServiceDiscoveryDeviceLister::Delegate void OnDeviceChanged( const std::string& service_type,
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc index 4e99b80d..b56953c5 100644 --- a/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc +++ b/chrome/browser/media/webrtc/webrtc_event_log_manager_local.cc
@@ -184,8 +184,7 @@ // In the unlikely case that this filename is already taken, find a unique // number to append to the filename, if possible. - int unique_number = - base::GetUniquePathNumber(file_path, base::FilePath::StringType()); + int unique_number = base::GetUniquePathNumber(file_path); if (unique_number < 0) { return; // No available file path was found. } else if (unique_number != 0) {
diff --git a/chrome/browser/net/cookie_policy_browsertest.cc b/chrome/browser/net/cookie_policy_browsertest.cc index 8045036..d856955 100644 --- a/chrome/browser/net/cookie_policy_browsertest.cc +++ b/chrome/browser/net/cookie_policy_browsertest.cc
@@ -5,16 +5,21 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/macros.h" +#include "base/path_service.h" #include "base/strings/stringprintf.h" +#include "base/test/scoped_feature_list.h" +#include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" -#include "components/content_settings/core/browser/host_content_settings_map.h" +#include "components/content_settings/core/browser/cookie_settings.h" +#include "components/content_settings/core/common/features.h" #include "components/content_settings/core/common/pref_names.h" #include "components/prefs/pref_service.h" +#include "content/public/common/content_paths.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/test_navigation_observer.h" #include "net/dns/mock_host_resolver.h" @@ -24,12 +29,22 @@ namespace { +// "ServiceWorker", "CacheStorage" are not available because the test server +// runs on http. +const std::vector<std::string> kStorageTypes{ + "Cookie", "LocalStorage", "FileSystem", + "SessionStorage", "IndexedDb", "WebSql", +}; + class CookiePolicyBrowserTest : public InProcessBrowserTest { protected: CookiePolicyBrowserTest() {} void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); + base::FilePath path; + base::PathService::Get(content::DIR_TEST_DATA, &path); + embedded_test_server()->ServeFilesFromDirectory(path); ASSERT_TRUE(embedded_test_server()->Start()); } @@ -51,13 +66,9 @@ } void ExpectFrameContent(const std::string& expected) { - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - content::RenderFrameHost* nested = - ChildFrameAt(web_contents->GetMainFrame(), 0); std::string content; ASSERT_TRUE(ExecuteScriptAndExtractString( - nested, + GetFrame(), "window.domAutomationController.send(document.body.textContent)", &content)); EXPECT_EQ(expected, content); @@ -67,25 +78,18 @@ GURL url(embedded_test_server()->GetURL(host, path)); content::WebContents* web_contents = browser()->tab_strip_model()->GetActiveWebContents(); - content::RenderFrameHost* nested = - ChildFrameAt(web_contents->GetMainFrame(), 0); content::TestNavigationObserver load_observer(web_contents); ASSERT_TRUE(ExecuteScript( - nested, + GetFrame(), base::StringPrintf("document.body.querySelector('iframe').src = '%s';", url.spec().c_str()))); load_observer.Wait(); } void ExpectNestedFrameContent(const std::string& expected) { - content::WebContents* web_contents = - browser()->tab_strip_model()->GetActiveWebContents(); - content::RenderFrameHost* nested = - ChildFrameAt(web_contents->GetMainFrame(), 0); - content::RenderFrameHost* double_nested = ChildFrameAt(nested, 0); std::string content; ASSERT_TRUE(ExecuteScriptAndExtractString( - double_nested, + GetNestedFrame(), "window.domAutomationController.send(document.body.textContent)", &content)); EXPECT_EQ(expected, content); @@ -98,10 +102,53 @@ embedded_test_server()->GetURL(host, "/"))); } + void SetStorageForFrame(content::RenderFrameHost* frame) { + for (const auto& data_type : kStorageTypes) { + bool data; + EXPECT_TRUE(content::ExecuteScriptAndExtractBool( + frame, "set" + data_type + "()", &data)); + EXPECT_TRUE(data) << data_type; + } + } + + void ExpectStorageForFrame(content::RenderFrameHost* frame, bool expected) { + for (const auto& data_type : kStorageTypes) { + bool data; + EXPECT_TRUE(content::ExecuteScriptAndExtractBool( + frame, "try { has" + data_type + "(); } catch(e) { failure_(); }", + &data)); + EXPECT_EQ(expected, data) << data_type; + } + } + + content::RenderFrameHost* GetFrame() { + content::WebContents* web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + return ChildFrameAt(web_contents->GetMainFrame(), 0); + } + + content::RenderFrameHost* GetNestedFrame() { + return ChildFrameAt(GetFrame(), 0); + } + private: DISALLOW_COPY_AND_ASSIGN(CookiePolicyBrowserTest); }; +// CookiePolicyBrowserTest with a feature list that enables usage of +// TopLevelOrigin for CookieSettings. This is only required until this +// behavior can be enabled by default. https://crbug.com/988398 +class CookiePolicyTopLevelOriginBrowserTest : public CookiePolicyBrowserTest { + public: + CookiePolicyTopLevelOriginBrowserTest() { + enable_cookie_controls_.InitAndEnableFeature( + content_settings::kImprovedCookieControls); + } + + private: + base::test::ScopedFeatureList enable_cookie_controls_; +}; + // Visits a page that sets a first-party cookie. IN_PROC_BROWSER_TEST_F(CookiePolicyBrowserTest, AllowFirstPartyCookies) { SetBlockThirdPartyCookies(false); @@ -264,4 +311,219 @@ ExpectNestedFrameContent("None"); } +IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest, + ThirdPartyCookiesIFrameExceptions) { + SetBlockThirdPartyCookies(true); + + // Set a cookie on `b.com`. + content::SetCookie(browser()->profile(), + embedded_test_server()->GetURL("b.com", "/"), + "thirdparty"); + ExpectCookiesOnHost("b.com", "thirdparty"); + + // Allow all requests to b.com to have cookies. + auto cookie_settings = + CookieSettingsFactory::GetForProfile(browser()->profile()); + GURL url = embedded_test_server()->GetURL("b.com", "/"); + cookie_settings->SetCookieSetting(url, ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + + // Navigate iframe to a cross-site, cookie-reading endpoint, and verify that + // the cookie is sent: + NavigateFrameTo("b.com", "/echoheader?cookie"); + ExpectFrameContent("thirdparty"); + + // Navigate iframe to a cross-site frame with a frame, and navigate _that_ + // frame to a cross-site page that echos the cookie header, and verify that + // the cookie is sent: + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("b.com", "/echoheader?cookie"); + ExpectNestedFrameContent("thirdparty"); + + // Navigate iframe to a cross-site frame with a frame, and navigate _that_ + // frame to a distinct cross-site page that echos the cookie header, and + // verify that the cookie is sent: + NavigateFrameTo("c.com", "/iframe.html"); + NavigateNestedFrameTo("b.com", "/echoheader?cookie"); + ExpectNestedFrameContent("thirdparty"); +} + +IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest, + ThirdPartyCookiesIFrameThirdPartyExceptions) { + SetBlockThirdPartyCookies(true); + + // Set a cookie on `b.com`. + content::SetCookie(browser()->profile(), + embedded_test_server()->GetURL("b.com", "/"), + "thirdparty"); + ExpectCookiesOnHost("b.com", "thirdparty"); + + // Allow all requests on the top frame domain a.com to have cookies. + auto cookie_settings = + CookieSettingsFactory::GetForProfile(browser()->profile()); + GURL url = embedded_test_server()->GetURL("a.com", "/"); + cookie_settings->SetThirdPartyCookieSetting( + url, ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + + // Navigate iframe to a cross-site, cookie-reading endpoint, and verify that + // the cookie is sent: + NavigateFrameTo("b.com", "/echoheader?cookie"); + ExpectFrameContent("thirdparty"); + + // Navigate iframe to a cross-site frame with a frame, and navigate _that_ + // frame to a cross-site page that echos the cookie header, and verify that + // the cookie is sent: + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("b.com", "/echoheader?cookie"); + ExpectNestedFrameContent("thirdparty"); + + // Navigate iframe to a cross-site frame with a frame, and navigate _that_ + // frame to a distinct cross-site page that echos the cookie header, and + // verify that the cookie is sent: + NavigateFrameTo("c.com", "/iframe.html"); + NavigateNestedFrameTo("b.com", "/echoheader?cookie"); + ExpectNestedFrameContent("thirdparty"); +} + +IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest, + ThirdPartyIFrameStorage) { + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetFrame(), false); + SetStorageForFrame(GetFrame()); + ExpectStorageForFrame(GetFrame(), true); + + SetBlockThirdPartyCookies(true); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetFrame(), false); + + // Allow all requests to b.com to access storage. + auto cookie_settings = + CookieSettingsFactory::GetForProfile(browser()->profile()); + GURL a_url = embedded_test_server()->GetURL("a.com", "/"); + GURL b_url = embedded_test_server()->GetURL("b.com", "/"); + cookie_settings->SetCookieSetting(b_url, + ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetFrame(), true); + + // Remove ALLOW setting. + cookie_settings->ResetCookieSetting(b_url); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetFrame(), false); + + // Allow all third-parties on a.com to access storage. + cookie_settings->SetThirdPartyCookieSetting( + a_url, ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetFrame(), true); +} + +IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest, + NestedThirdPartyIFrameStorage) { + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("c.com", "/browsing_data/site_data.html"); + + ExpectStorageForFrame(GetNestedFrame(), false); + SetStorageForFrame(GetNestedFrame()); + ExpectStorageForFrame(GetNestedFrame(), true); + + SetBlockThirdPartyCookies(true); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("c.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), false); + + // Allow all requests to b.com to access storage. + auto cookie_settings = + CookieSettingsFactory::GetForProfile(browser()->profile()); + GURL a_url = embedded_test_server()->GetURL("a.com", "/"); + GURL c_url = embedded_test_server()->GetURL("c.com", "/"); + cookie_settings->SetCookieSetting(c_url, + ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("c.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), true); + + // Remove ALLOW setting. + cookie_settings->ResetCookieSetting(c_url); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("c.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), false); + + // Allow all third-parties on a.com to access storage. + cookie_settings->SetThirdPartyCookieSetting( + a_url, ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("c.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), true); +} + +// TODO(crbug.com/989926): Nested first-party iframes behave incorrectly. +IN_PROC_BROWSER_TEST_F(CookiePolicyTopLevelOriginBrowserTest, + DISABLED_NestedFirstPartyIFrameStorage) { + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("a.com", "/browsing_data/site_data.html"); + + ExpectStorageForFrame(GetNestedFrame(), false); + SetStorageForFrame(GetNestedFrame()); + ExpectStorageForFrame(GetNestedFrame(), true); + + SetBlockThirdPartyCookies(true); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("a.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), false); + + // Allow all requests to b.com to access storage. + auto cookie_settings = + CookieSettingsFactory::GetForProfile(browser()->profile()); + GURL a_url = embedded_test_server()->GetURL("a.com", "/"); + cookie_settings->SetCookieSetting(a_url, + ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("a.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), true); + + // Remove ALLOW setting. + cookie_settings->ResetCookieSetting(a_url); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("a.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), false); + + // Allow all third-parties on a.com to access storage. + cookie_settings->SetThirdPartyCookieSetting( + a_url, ContentSetting::CONTENT_SETTING_ALLOW); + + NavigateToPageWithFrame("a.com"); + NavigateFrameTo("b.com", "/iframe.html"); + NavigateNestedFrameTo("a.com", "/browsing_data/site_data.html"); + ExpectStorageForFrame(GetNestedFrame(), true); +} + } // namespace
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc index 77db734..7135c1b 100644 --- a/chrome/browser/net/system_network_context_manager.cc +++ b/chrome/browser/net/system_network_context_manager.cc
@@ -31,6 +31,7 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/pref_names.h" #include "components/certificate_transparency/ct_known_logs.h" +#include "components/flags_ui/pref_service_flags_storage.h" #include "components/net_log/net_export_file_writer.h" #include "components/network_session_configurator/common/network_features.h" #include "components/os_crypt/os_crypt.h" @@ -387,6 +388,24 @@ local_state_->SetDefaultPrefValue(prefs::kDnsOverHttpsTemplates, base::Value(default_doh_templates)); + // If the user has explicitly enabled or disabled the DoH experiment in + // chrome://flags, store that choice in the user prefs so that it can be + // persisted after the experiment ends. Also make sure to remove the stored + // prefs value if the user has changed their chrome://flags selection to the + // default. + flags_ui::PrefServiceFlagsStorage flags_storage(local_state_); + std::set<std::string> entries = flags_storage.GetFlags(); + if (entries.count("dns-over-https@1")) { + // The user has "Enabled" selected. + local_state_->SetString(prefs::kDnsOverHttpsMode, "automatic"); + } else if (entries.count("dns-over-https@2")) { + // The user has "Disabled" selected. + local_state_->SetString(prefs::kDnsOverHttpsMode, "off"); + } else { + // The user has "Default" selected. + local_state_->ClearPref(prefs::kDnsOverHttpsMode); + } + PrefChangeRegistrar::NamedChangeCallback dns_pref_callback = base::BindRepeating(&OnStubResolverConfigChanged, base::Unretained(local_state_));
diff --git a/chrome/browser/no_best_effort_tasks_browsertest.cc b/chrome/browser/no_best_effort_tasks_browsertest.cc index a500d2b..91972d32 100644 --- a/chrome/browser/no_best_effort_tasks_browsertest.cc +++ b/chrome/browser/no_best_effort_tasks_browsertest.cc
@@ -225,3 +225,25 @@ } } #endif // BUILDFLAG(ENABLE_EXTENSIONS) + +// Verify that Blob XMLHttpRequest finishes without running BEST_EFFORT tasks. +// Regression test for https://crbug.com/989868. +IN_PROC_BROWSER_TEST_F(NoBestEffortTasksTest, BlobXMLHttpRequest) { + ASSERT_TRUE(embedded_test_server()->Start()); + ui_test_utils::NavigateToURL(browser(), + embedded_test_server()->GetURL("/empty.html")); + const char kScript[] = R"( + new Promise(function (resolve, reject) { + const xhr = new XMLHttpRequest(); + xhr.open("GET", "./empty.html?", true); + xhr.responseType = "blob"; + xhr.onload = () => { + resolve('DONE'); + }; + xhr.send(); + }) + )"; + EXPECT_EQ("DONE", + content::EvalJs( + browser()->tab_strip_model()->GetActiveWebContents(), kScript)); +}
diff --git a/chrome/browser/predictors/loading_predictor_browsertest.cc b/chrome/browser/predictors/loading_predictor_browsertest.cc index c99ec11..933584a8 100644 --- a/chrome/browser/predictors/loading_predictor_browsertest.cc +++ b/chrome/browser/predictors/loading_predictor_browsertest.cc
@@ -39,6 +39,7 @@ #include "content/public/common/referrer.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/simple_url_loader_test_helper.h" +#include "net/base/escape.h" #include "net/base/features.h" #include "net/base/network_isolation_key.h" #include "net/dns/mock_host_resolver.h" @@ -396,6 +397,8 @@ ASSERT_TRUE(embedded_test_server()->InitializeAndListen()); embedded_test_server()->RegisterRequestHandler(base::BindRepeating( &LoadingPredictorBrowserTest::HandleFaviconRequest)); + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &LoadingPredictorBrowserTest::HandleCacheRedirectRequest)); InProcessBrowserTest::SetUp(); } @@ -486,6 +489,29 @@ return http_response; } + static std::unique_ptr<net::test_server::HttpResponse> + HandleCacheRedirectRequest(const net::test_server::HttpRequest& request) { + if (!base::StartsWith(request.relative_url, "/cached-redirect?", + base::CompareCase::INSENSITIVE_ASCII)) { + return std::unique_ptr<net::test_server::HttpResponse>(); + } + + GURL request_url = request.GetURL(); + std::string dest = + net::UnescapeBinaryURLComponent(request_url.query_piece()); + + auto http_response = + std::make_unique<net::test_server::BasicHttpResponse>(); + http_response->set_code(net::HTTP_MOVED_PERMANENTLY); + http_response->AddCustomHeader("Location", dest); + http_response->set_content_type("text/html"); + http_response->set_content(base::StringPrintf( + "<html><head></head><body>Redirecting to %s</body></html>", + dest.c_str())); + http_response->AddCustomHeader("Cache-Control", "max-age=6000"); + return http_response; + } + private: LoadingPredictor* loading_predictor_ = nullptr; std::unique_ptr<ConnectionListener> connection_listener_; @@ -700,16 +726,6 @@ prediction = GetPreconnectPrediction(original_url); EXPECT_FALSE(prediction); - // TODO(https://crbug.com/987735): These predictions should match |requests| - // should use |redirect_url|'s origin. - url::Origin original_origin = url::Origin::Create(original_url); - std::vector<PreconnectRequest> requests2; - for (auto* const host : kHtmlSubresourcesHosts) { - requests2.emplace_back( - embedded_test_server()->GetURL(host, "/"), 1, - net::NetworkIsolationKey(original_origin, original_origin)); - } - // The predictor will start predict a redirect after the second navigation. ui_test_utils::NavigateToURL(browser(), original_url); prediction = GetPreconnectPrediction(original_url); @@ -717,7 +733,7 @@ EXPECT_EQ(prediction->is_redirected, true); EXPECT_EQ(prediction->host, redirect_url.host()); EXPECT_THAT(prediction->requests, - testing::UnorderedElementsAreArray(requests2)); + testing::UnorderedElementsAreArray(requests)); } // Tests that the LoadingPredictor performs preresolving/preconnecting for a @@ -975,7 +991,7 @@ // both when the predictor is populated and when it isn't. IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest, LoadingPredictorNoRedirects) { - // Cache resources needed by navigations, so so the only sockets created + // Cache resources needed by navigations, so the only sockets created // during navigations should be for the two preconnects. CacheFavIcon(); GURL cacheable_url = embedded_test_server()->GetURL("/cachetime"); @@ -1013,6 +1029,103 @@ } } +// Make sure that the right NetworkIsolationKey is used by the LoadingPredictor, +// both when the predictor is populated and when it isn't. +IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest, + LoadingPredictorWithRedirects) { + // Cache resources needed by navigations, so the only connections to the + // tracked server created during navigations should be for preconnects. + CacheFavIcon(); + GURL cacheable_url = embedded_test_server()->GetURL("/cachetime"); + CacheUrl(cacheable_url); + + GURL redirecting_url = preconnecting_test_server()->GetURL( + "/server-redirect?" + cacheable_url.spec()); + + // Learn the redirects from initial navigation. + ui_test_utils::NavigateToURL(browser(), redirecting_url); + EXPECT_EQ(0u, connection_tracker()->GetAcceptedSocketCount()); + EXPECT_EQ(0u, connection_tracker()->GetReadSocketCount()); + + // The next navigation should preconnect. It won't use the preconnected + // socket, since the destination resource is still in the cache. + auto observer = NavigateToURLAsync(redirecting_url); + observer->WaitForNavigationFinished(); + connection_tracker()->WaitForAcceptedConnections(1); + EXPECT_EQ(0u, connection_tracker()->GetReadSocketCount()); + + // Have the page fetch a subresource, which should use one of the + // preconnects triggered by the above navigation, due to the matching + // NetworkIsolationKey. Do this instead of a navigation to a non-cached URL + // to avoid triggering more preconnects. + std::string fetch_resource = base::StringPrintf( + "(async () => {" + " var resp = (await fetch('%s'));" + " return resp.status; })();", + embedded_test_server()->GetURL("/echo").spec().c_str()); + EXPECT_EQ( + 200, + EvalJs( + browser()->tab_strip_model()->GetActiveWebContents()->GetMainFrame(), + fetch_resource)); + + EXPECT_EQ(1u, connection_tracker()->GetAcceptedSocketCount()); + EXPECT_EQ(1u, connection_tracker()->GetReadSocketCount()); +} + +// Checks the opposite of the above test - tests that even when a redirect is +// predicted, preconnects are still made to the original origin using the +// correct NetworkIsolationKey. +IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest, + LoadingPredictorWithRedirects2) { + // Cache the redirect, so the only connections to the tracked server created + // during navigations should be for preconnects. + GURL destination_url = preconnecting_test_server()->GetURL("/cachetime"); + GURL redirecting_url = embedded_test_server()->GetURL("/cached-redirect?" + + destination_url.spec()); + CacheUrl(redirecting_url); + + // The first navigation learns to preconnect based on the redirect, and the + // second actually preconnects to the untracked server. All navigations should + // preconnect twice to the tracked server. + for (int i = 0; i < 2; ++i) { + if (i == 0) { + // NavigateToURL waits long enough to ensure information from the + // navigation is learned, while WaitForNavigationFinished() does not. + ui_test_utils::NavigateToURL(browser(), redirecting_url); + } else { + auto observer = NavigateToURLAsync(redirecting_url); + observer->WaitForNavigationFinished(); + } + connection_tracker()->WaitForAcceptedConnections(2); + EXPECT_EQ(0u, connection_tracker()->GetReadSocketCount()); + + // Verify that the preconnects were made using the |redirecting_url|'s + // NetworkIsolationKey. To do this, make a request using the tracked + // server's NetworkIsolationKey, and verify it used one of the existing + // sockets. + auto request = std::make_unique<network::ResourceRequest>(); + request->url = embedded_test_server()->GetURL("/echo"); + content::SimpleURLLoaderTestHelper simple_loader_helper; + url::Origin origin = url::Origin::Create(request->url); + request->trusted_params = network::ResourceRequest::TrustedParams(); + request->trusted_params->network_isolation_key = + net::NetworkIsolationKey(origin, origin); + std::unique_ptr<network::SimpleURLLoader> simple_loader = + network::SimpleURLLoader::Create(std::move(request), + TRAFFIC_ANNOTATION_FOR_TESTS); + simple_loader->DownloadToStringOfUnboundedSizeUntilCrashAndDie( + browser()->profile()->GetURLLoaderFactory().get(), + simple_loader_helper.GetCallback()); + simple_loader_helper.WaitForCallback(); + ASSERT_TRUE(simple_loader_helper.response_body()); + EXPECT_EQ(2u, connection_tracker()->GetAcceptedSocketCount()); + EXPECT_EQ(1u, connection_tracker()->GetReadSocketCount()); + + ResetNetworkState(); + } +} + IN_PROC_BROWSER_TEST_P(LoadingPredictorNetworkIsolationKeyBrowserTest, LinkRelPreconnectMainFrame) { const char kHost1[] = "host1.test";
diff --git a/chrome/browser/predictors/loading_test_util.cc b/chrome/browser/predictors/loading_test_util.cc index 9c9d6c9..7c400ad 100644 --- a/chrome/browser/predictors/loading_test_util.cc +++ b/chrome/browser/predictors/loading_test_util.cc
@@ -33,10 +33,14 @@ const GURL& url, int number_of_hits, int number_of_misses, - int consecutive_misses) { + int consecutive_misses, + bool include_scheme, + bool include_port) { redirect->set_url(url.host()); - redirect->set_url_scheme(url.scheme()); - redirect->set_url_port(url.EffectiveIntPort()); + if (include_scheme) + redirect->set_url_scheme(url.scheme()); + if (include_port) + redirect->set_url_port(url.EffectiveIntPort()); redirect->set_number_of_hits(number_of_hits); redirect->set_number_of_misses(number_of_misses); redirect->set_consecutive_misses(consecutive_misses);
diff --git a/chrome/browser/predictors/loading_test_util.h b/chrome/browser/predictors/loading_test_util.h index 8923b83..6a94fb554 100644 --- a/chrome/browser/predictors/loading_test_util.h +++ b/chrome/browser/predictors/loading_test_util.h
@@ -35,11 +35,15 @@ MOCK_METHOD1(RecordPageRequestSummaryProxy, void(PageRequestSummary*)); }; +// |include_scheme| and |include_port| can be set to false to simulate legacy +// data, which doesn't have new fields. void InitializeRedirectStat(RedirectStat* redirect, const GURL& url, int number_of_hits, int number_of_misses, - int consecutive_misses); + int consecutive_misses, + bool include_scheme = true, + bool include_port = true); void InitializeOriginStat(OriginStat* origin_stat, const std::string& origin,
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc index c0f50e42..2c4a0f5 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "base/rand_util.h" +#include "base/strings/string_number_conversions.h" #include "base/time/time.h" #include "base/trace_event/trace_event.h" #include "chrome/browser/history/history_service_factory.h" @@ -57,6 +58,12 @@ origin_data->InitializeOnDBSequence(); } +GURL CreateRedirectURL(const std::string& scheme, + const std::string& host, + std::uint16_t port) { + return GURL(scheme + "://" + host + ":" + base::NumberToString(port)); +} + } // namespace PreconnectRequest::PreconnectRequest( @@ -77,18 +84,18 @@ //////////////////////////////////////////////////////////////////////////////// // ResourcePrefetchPredictor static functions. -bool ResourcePrefetchPredictor::GetRedirectEndpoint( - const std::string& entry_point, +bool ResourcePrefetchPredictor::GetRedirectOrigin( + const url::Origin& entry_origin, const RedirectDataMap& redirect_data, - std::string* redirect_endpoint) const { - DCHECK(redirect_endpoint); + url::Origin* redirect_origin) { + DCHECK(redirect_origin); RedirectData data; - bool exists = redirect_data.TryGetData(entry_point, &data); + bool exists = redirect_data.TryGetData(entry_origin.host(), &data); if (!exists) { // Fallback to fetching URLs based on the incoming URL/host. By default // the predictor is confident that there is no redirect. - *redirect_endpoint = entry_point; + *redirect_origin = entry_origin; return true; } @@ -109,14 +116,37 @@ // The predictor doesn't apply a minimum-number-of-hits threshold to // the no-redirect case because the no-redirect is a default assumption. const RedirectStat& redirect = data.redirect_endpoints(0); + if (ComputeRedirectConfidence(redirect) < kMinRedirectConfidenceToTriggerPrefetch || (redirect.number_of_hits() < kMinRedirectHitsToTriggerPrefetch && - redirect.url() != entry_point)) { + redirect.url() != entry_origin.host())) { return false; } - *redirect_endpoint = redirect.url(); + // Create a GURL from |redirect|, and get the origin from it. Origins can + // be created be directly passing in scheme, host, and port, but the class + // DCHECKs if any of them are invalid, and best not to DCHECK when loading bad + // data from disk. GURL does not DCHECK on bad input, so safest to rely on its + // logic, though more computationally expensive. + + GURL redirect_url; + // Old entries may have no scheme or port. + if (redirect.has_url_scheme() && redirect.has_url_port()) { + redirect_url = CreateRedirectURL(redirect.url_scheme(), redirect.url(), + redirect.url_port()); + } + + // If there was no scheme or port, or they don't make for a valid URL (most + // likely due to using 0 or an empty scheme as default values), default to + // HTTPS / port 443. + if (!redirect_url.is_valid()) + redirect_url = CreateRedirectURL("https", redirect.url(), 443); + + if (!redirect_url.is_valid()) + return false; + + *redirect_origin = url::Origin::Create(redirect_url); return true; } @@ -210,30 +240,25 @@ if (initialization_state_ != INITIALIZED) return false; - std::string host = url.host(); - std::string redirect_endpoint; - if (!GetRedirectEndpoint(host, *host_redirect_data_, &redirect_endpoint)) + url::Origin url_origin = url::Origin::Create(url); + url::Origin redirect_origin; + if (!GetRedirectOrigin(url_origin, *host_redirect_data_, &redirect_origin)) { return false; + } OriginData data; - if (!origin_data_->TryGetData(redirect_endpoint, &data)) + if (!origin_data_->TryGetData(redirect_origin.host(), &data)) return false; if (prediction) { - prediction->host = redirect_endpoint; - prediction->is_redirected = (host != redirect_endpoint); + prediction->host = redirect_origin.host(); + prediction->is_redirected = (redirect_origin != url_origin); } bool has_any_prediction = false; - // TODO(https://crbug.com/987735): Use the NetworkIsolationKey of the final - // destination in the case of redirects. This will require recording the port, - // which is not currently logged. That will not result in using the correct - // NetworkIsolationKey in the case of intermediary redirects, but given the - // relatively low accurace of redirect predictions, seems likely not worth - // fixing. - url::Origin origin = url::Origin::Create(url); - net::NetworkIsolationKey network_isolation_key(origin, origin); + net::NetworkIsolationKey network_isolation_key(redirect_origin, + redirect_origin); for (const OriginStat& origin : data.origins()) { float confidence = static_cast<float>(origin.number_of_hits()) /
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h index 9edc2df3..86ae7294 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor.h +++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -190,7 +190,7 @@ FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, GetCorrectPLT); FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, PopulatePrefetcherRequest); - FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, GetRedirectEndpoint); + FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, GetRedirectOrigin); FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, GetPrefetchData); FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, TestPredictPreconnectOrigins); @@ -208,14 +208,14 @@ }; // Returns true iff one of the following conditions is true - // * |redirect_data| contains confident redirect endpoint for |entry_point| - // and assigns it to the |redirect_endpoint| + // * |redirect_data| contains confident redirect origin for |entry_origin| + // and assigns it to the |redirect_origin| // - // * |redirect_data| doens't contain an entry for |entry_point| and assigns - // |entry_point| to the |redirect_endpoint|. - bool GetRedirectEndpoint(const std::string& entry_point, - const RedirectDataMap& redirect_data, - std::string* redirect_endpoint) const; + // * |redirect_data| doesn't contain an entry for |entry_origin| and assigns + // |entry_origin| to the |redirect_origin|. + static bool GetRedirectOrigin(const url::Origin& entry_origin, + const RedirectDataMap& redirect_data, + url::Origin* redirect_origin); // Callback for the task to read the predictor database. Takes ownership of // all arguments.
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc index 43b7c9c..9b82442 100644 --- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc +++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -639,33 +639,40 @@ EXPECT_TRUE(mock_tables_->origin_table_.data_.empty()); } -TEST_F(ResourcePrefetchPredictorTest, GetRedirectEndpoint) { +TEST_F(ResourcePrefetchPredictorTest, GetRedirectOrigin) { auto& redirect_data = *predictor_->host_redirect_data_; - std::string redirect_endpoint; + url::Origin bbc_origin = url::Origin::Create(GURL("https://bbc.com/")); + url::Origin redirect_origin; // Returns the initial url if data_map doesn't contain an entry for the url. - EXPECT_TRUE(predictor_->GetRedirectEndpoint("bbc.com", redirect_data, - &redirect_endpoint)); - EXPECT_EQ(redirect_endpoint, "bbc.com"); + EXPECT_TRUE(predictor_->GetRedirectOrigin(bbc_origin, redirect_data, + &redirect_origin)); + EXPECT_EQ(bbc_origin, redirect_origin); + url::Origin nyt_origin = url::Origin::Create(GURL("https://nyt.com/")); // The data to be requested for the confident endpoint. - RedirectData nyt = CreateRedirectData("nyt.com", 1); - InitializeRedirectStat(nyt.add_redirect_endpoints(), - GURL("https://mobile.nytimes.com"), 10, 0, 0); + RedirectData nyt = CreateRedirectData(nyt_origin.host(), 1); + GURL nyt_redirect_url("https://mobile.nytimes.com:8080/"); + url::Origin nyt_redirect_origin = url::Origin::Create(nyt_redirect_url); + InitializeRedirectStat(nyt.add_redirect_endpoints(), nyt_redirect_url, 10, 0, + 0); redirect_data.UpdateData(nyt.primary_key(), nyt); - EXPECT_TRUE(predictor_->GetRedirectEndpoint("nyt.com", redirect_data, - &redirect_endpoint)); - EXPECT_EQ(redirect_endpoint, "mobile.nytimes.com"); + EXPECT_TRUE(predictor_->GetRedirectOrigin(nyt_origin, redirect_data, + &redirect_origin)); + EXPECT_EQ(nyt_redirect_origin, redirect_origin); + url::Origin facebook_origin = url::Origin::Create(GURL("http://fb.com/")); // The data to check negative result due not enough confidence. - RedirectData facebook = CreateRedirectData("fb.com", 3); + RedirectData facebook = CreateRedirectData(facebook_origin.host(), 3); + GURL facebook_redirect_url("https://fb.com/"); InitializeRedirectStat(facebook.add_redirect_endpoints(), - GURL("https://facebook.com"), 5, 5, 0); + facebook_redirect_url, 5, 5, 0); redirect_data.UpdateData(facebook.primary_key(), facebook); - EXPECT_FALSE(predictor_->GetRedirectEndpoint("fb.com", redirect_data, - &redirect_endpoint)); + EXPECT_FALSE(predictor_->GetRedirectOrigin(facebook_origin, redirect_data, + &redirect_origin)); // The data to check negative result due ambiguity. - RedirectData google = CreateRedirectData("google.com", 4); + url::Origin google_origin = url::Origin::Create(GURL("https://google.com/")); + RedirectData google = CreateRedirectData(google_origin.host(), 4); InitializeRedirectStat(google.add_redirect_endpoints(), GURL("https://google.com"), 10, 0, 0); InitializeRedirectStat(google.add_redirect_endpoints(), @@ -673,8 +680,40 @@ InitializeRedirectStat(google.add_redirect_endpoints(), GURL("https://google.ws"), 20, 20, 0); redirect_data.UpdateData(google.primary_key(), google); - EXPECT_FALSE(predictor_->GetRedirectEndpoint("google.com", redirect_data, - &redirect_endpoint)); + EXPECT_FALSE(predictor_->GetRedirectOrigin(google_origin, redirect_data, + &redirect_origin)); + + // Check the case of a redirect with no port or scheme in the database. The + // redirected origin should default to HTTPS on port 443, if either is + // missing. + + url::Origin no_port_origin = + url::Origin::Create(GURL("https://no-port.test/")); + RedirectData no_port = CreateRedirectData(no_port_origin.host(), 1); + GURL no_port_redirect_url("http://redirect-destination.no-port.test/"); + url::Origin no_port_redirect_origin = + url::Origin::Create(GURL("https://redirect-destination.no-port.test/")); + InitializeRedirectStat(no_port.add_redirect_endpoints(), no_port_redirect_url, + 10, 0, 0, true /* include_scheme */, + false /* include_port */); + redirect_data.UpdateData(no_port.primary_key(), no_port); + EXPECT_TRUE(predictor_->GetRedirectOrigin(no_port_origin, redirect_data, + &redirect_origin)); + EXPECT_EQ(no_port_redirect_origin, redirect_origin); + + url::Origin no_scheme_origin = + url::Origin::Create(GURL("https://no-scheme.test/")); + RedirectData no_scheme = CreateRedirectData(no_scheme_origin.host(), 1); + GURL no_scheme_redirect_url("http://redirect-destination.no-scheme.test/"); + url::Origin no_scheme_redirect_origin = + url::Origin::Create(GURL("https://redirect-destination.no-scheme.test/")); + InitializeRedirectStat(no_scheme.add_redirect_endpoints(), + no_scheme_redirect_url, 10, 0, 0, + true /* include_scheme */, false /* include_port */); + redirect_data.UpdateData(no_scheme.primary_key(), no_scheme); + EXPECT_TRUE(predictor_->GetRedirectOrigin(no_scheme_origin, redirect_data, + &redirect_origin)); + EXPECT_EQ(no_scheme_redirect_origin, redirect_origin); } TEST_F(ResourcePrefetchPredictorTest, TestPredictPreconnectOrigins) { @@ -731,13 +770,18 @@ true); // High confidence - preconnect. predictor_->origin_data_->UpdateData(www_google.host(), www_google); + const url::Origin www_google_origin = + url::Origin::Create(GURL("https://www.google.com")); + const net::NetworkIsolationKey www_google_network_isolation_key( + www_google_origin, www_google_origin); prediction = std::make_unique<PreconnectPrediction>(); EXPECT_TRUE(predictor_->IsUrlPreconnectable(main_frame_url)); EXPECT_TRUE( predictor_->PredictPreconnectOrigins(main_frame_url, prediction.get())); - EXPECT_EQ(*prediction, CreatePreconnectPrediction("www.google.com", true, - {{GURL(gen_origin(4)), 1, - network_isolation_key}})); + EXPECT_EQ(*prediction, + CreatePreconnectPrediction( + "www.google.com", true, + {{GURL(gen_origin(4)), 1, www_google_network_isolation_key}})); } } // namespace predictors
diff --git a/chrome/browser/printing/print_view_manager_basic.cc b/chrome/browser/printing/print_view_manager_basic.cc index 326396c..160845d 100644 --- a/chrome/browser/printing/print_view_manager_basic.cc +++ b/chrome/browser/printing/print_view_manager_basic.cc
@@ -26,7 +26,7 @@ #if defined(OS_ANDROID) void PrintViewManagerBasic::PdfWritingDone(int page_count) { if (pdf_writing_done_callback_) - pdf_writing_done_callback_.Run(page_count); + std::move(pdf_writing_done_callback_).Run(page_count); } #endif
diff --git a/chrome/browser/resources/bookmarks/shared_style.html b/chrome/browser/resources/bookmarks/shared_style.html index 22bfc62..723f2db2 100644 --- a/chrome/browser/resources/bookmarks/shared_style.html +++ b/chrome/browser/resources/bookmarks/shared_style.html
@@ -56,6 +56,9 @@ .folder-icon { content: url(chrome://theme/IDR_FOLDER_CLOSED); + height: 20px; + min-width: 20px; + width: 20px; } <if expr="is_macosx or is_ios">
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/console_tts.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/console_tts.js index 0c3896c..f872404 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/console_tts.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/console_tts.js
@@ -44,7 +44,7 @@ logStr += ' category=' + properties.category; } logStr += ' "' + textString + '"'; - LogStore.getInstance().writeTextLog(logStr, TextLog.LogType.SPEECH); + LogStore.getInstance().writeTextLog(logStr, LogStore.LogType.SPEECH); console.log(logStr); } return this;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/event_stream_logger.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/event_stream_logger.js index d18b3c7..a33de06 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/event_stream_logger.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/event_stream_logger.js
@@ -60,7 +60,7 @@ logStr += ', RootName = ' + evt.target.root.name; logStr += ', DocumentURL = ' + evt.target.docUrl; console.log(logStr); - LogStore.getInstance().writeTextLog(logStr, TextLog.LogType.EVENT); + LogStore.getInstance().writeTextLog(logStr, LogStore.LogType.EVENT); }, /**
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/log.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/log.js index 47633ee..eea91c7 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/log.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/log.js
@@ -43,7 +43,7 @@ LogPage.LogStore = LogPage.backgroundWindow.LogStore.getInstance(); /** Create filter checkboxes. */ - for (var type of LogStore.logTypes()) { + for (var type of Object.values(LogStore.LogType)) { var label = document.createElement('label'); var input = document.createElement('input'); input.id = type + 'Filter'; @@ -65,7 +65,7 @@ }; var params = new URLSearchParams(location.search); - for (var type of LogStore.logTypes()) { + for (var type of Object.values(LogStore.LogType)) { var typeFilter = type + 'Filter'; LogPage.setFilterTypeEnabled(typeFilter, params.get(typeFilter)); } @@ -117,7 +117,7 @@ * update logs. */ LogPage.update = function() { - for (var type of LogStore.logTypes()) { + for (var type of Object.values(LogStore.LogType)) { var typeFilter = type + 'Filter'; var element = document.getElementById(typeFilter); element.checked = LogPage.urlPrefs_[typeFilter]; @@ -153,7 +153,7 @@ p.appendChild(timeStamp); /** Add hide tree button when logType is tree. */ - if (log[i].logType == TreeLog.LogType.TREE) { + if (log[i].logType == LogStore.LogType.TREE) { var toggle = document.createElement('label'); var toggleCheckbox = document.createElement('input'); toggleCheckbox.type = 'checkbox'; @@ -191,7 +191,7 @@ */ LogPage.createUrlParams = function() { var urlParams = []; - for (var type of LogStore.logTypes()) { + for (var type of Object.values(LogStore.LogType)) { var typeFilter = type + 'Filter'; urlParams.push(typeFilter + '=' + LogPage.urlPrefs_[typeFilter]); }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js index 20f9dff..c29c8da6 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/log_store.js
@@ -16,7 +16,7 @@ /** @constructor */ BaseLog = function(logType) { /** - * @type {!TextLog.LogType | !TreeLog.LogType} + * @type {!LogStore.LogType} */ this.logType = logType; @@ -33,7 +33,7 @@ /** * @param {string} logStr - * @param {!TextLog.LogType} logType + * @param {!LogStore.LogType} logType * @constructor * @extends {BaseLog} */ @@ -46,27 +46,11 @@ */ this.logStr_ = logStr; }; +goog.inherits(TextLog, BaseLog); -TextLog.prototype = { - __proto__: BaseLog.prototype, - - /** @override */ - toString: function() { - return this.logStr_; - }, -}; - -/** - * Filter type checkboxes are shown in this order at the log page. - * @enum {string} - */ -TextLog.LogType = { - SPEECH: 'speech', - SPEECH_RULE: 'speechRule', - BRAILLE: 'braille', - BRAILLE_RULE: 'brailleRule', - EARCON: 'earcon', - EVENT: 'event', +/** @override */ +TextLog.prototype.toString = function() { + return this.logStr_; }; /** @@ -75,7 +59,7 @@ * @extends {BaseLog} */ TreeLog = function(logTree) { - BaseLog.call(this, TreeLog.LogType.TREE); + BaseLog.call(this, LogStore.LogType.TREE); /** * @type {!TreeDumper} @@ -83,19 +67,11 @@ */ this.logTree_ = logTree; }; +goog.inherits(TreeLog, BaseLog); -TreeLog.prototype = { - __proto__: BaseLog.prototype, - - /** @override */ - toString: function() { - return this.logTree_.treeToString(); - }, -}; - -/** @enum {string} */ -TreeLog.LogType = { - TREE: 'tree', +/** @override */ +TreeLog.prototype.toString = function() { + return this.logTree_.treeToString(); }; /** @constructor */ @@ -124,32 +100,34 @@ LogStore.LOG_LIMIT = 3000; /** - * List of all LogTypes. - * @return {!Array<!TextLog.LogType | !TreeLog.LogType>} + * List of all LogType. + * Note that filter type checkboxes are shown in this order at the log page. + * @enum {string} */ -LogStore.logTypes = function() { - var types = []; - for (var type in TextLog.LogType) - types.push(TextLog.LogType[type]); - for (var type in TreeLog.LogType) - types.push(TreeLog.LogType[type]); - return types; +LogStore.LogType = { + SPEECH: 'speech', + SPEECH_RULE: 'speechRule', + BRAILLE: 'braille', + BRAILLE_RULE: 'brailleRule', + EARCON: 'earcon', + EVENT: 'event', + TREE: 'tree', }; /** * Creates logs of type |type| in order. * This is not the best way to create logs fast but * getLogsOfType() is not called often. - * @param {!TextLog.LogType} logType + * @param {!LogStore.LogType} LogType * @return {!Array<BaseLog>} */ -LogStore.prototype.getLogsOfType = function(logType) { +LogStore.prototype.getLogsOfType = function(LogType) { var returnLogs = []; for (var i = 0; i < LogStore.LOG_LIMIT; i++) { var index = (this.startIndex_ + i) % LogStore.LOG_LIMIT; if (!this.logs_[index]) continue; - if (this.logs_[index].logType == logType) + if (this.logs_[index].logType == LogType) returnLogs.push(this.logs_[index]); } return returnLogs; @@ -176,13 +154,13 @@ * Write a text log to this.logs_. * To add a message to logs, this function shuold be called. * @param {string} logContent - * @param {!TextLog.LogType} logType + * @param {!LogStore.LogType} LogType */ -LogStore.prototype.writeTextLog = function(logContent, logType) { +LogStore.prototype.writeTextLog = function(logContent, LogType) { if (this.shouldSkipOutput_()) return; - var log = new TextLog(logContent, logType); + var log = new TextLog(logContent, LogType); this.logs_[this.startIndex_] = log; this.startIndex_ += 1; if (this.startIndex_ == LogStore.LOG_LIMIT)
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js index 2e861aa..6a81790 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/next_earcons.js
@@ -63,7 +63,7 @@ return; } if (localStorage['enableEarconLogging'] == 'true') { - LogStore.getInstance().writeTextLog(earcon, TextLog.LogType.EARCON); + LogStore.getInstance().writeTextLog(earcon, LogStore.LogType.EARCON); console.log('Earcon ' + earcon); } if (ChromeVoxState.instance.currentRange &&
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js index d7b1c61e..1d03b2a 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -1052,7 +1052,7 @@ } if (this.speechRulesStr_.str) { LogStore.getInstance().writeTextLog( - this.speechRulesStr_.str, TextLog.LogType.SPEECH_RULE); + this.speechRulesStr_.str, LogStore.LogType.SPEECH_RULE); } // Braille. @@ -1078,7 +1078,7 @@ cvox.ChromeVox.braille.write(output); if (this.brailleRulesStr_.str) { LogStore.getInstance().writeTextLog( - this.brailleRulesStr_.str, TextLog.LogType.BRAILLE_RULE); + this.brailleRulesStr_.str, LogStore.LogType.BRAILLE_RULE); } }
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_background.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_background.js index bb0e4a1e..d610ef3 100644 --- a/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_background.js +++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/braille_background.js
@@ -77,7 +77,7 @@ if (localStorage['enableBrailleLogging'] == 'true') { var logStr = 'Braille "' + params.text.toString() + '"'; - LogStore.getInstance().writeTextLog(logStr, TextLog.LogType.BRAILLE); + LogStore.getInstance().writeTextLog(logStr, LogStore.LogType.BRAILLE); console.log(logStr); }
diff --git a/chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js b/chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js index 2ba8696..d052f0f 100644 --- a/chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js +++ b/chrome/browser/resources/chromeos/chromevox/host/chrome/classic_earcons.js
@@ -57,7 +57,7 @@ return; } if (localStorage['enableEarconLogging'] == 'true') { - LogStore.getInstance().writeTextLog(earcon, TextLog.LogType.EARCON); + LogStore.getInstance().writeTextLog(earcon, LogStore.LogType.EARCON); console.log('Earcon ' + earcon); }
diff --git a/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc b/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc index b52ff49..01ca698 100644 --- a/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc +++ b/chrome/browser/safe_browsing/test_safe_browsing_database_helper.cc
@@ -59,8 +59,7 @@ if (!base::Contains(*store_map, id)) { const base::FilePath store_path = base_store_path.InsertBeforeExtensionASCII(base::StringPrintf( - " (%d)", base::GetUniquePathNumber( - base_store_path, base::FilePath::StringType()))); + " (%d)", base::GetUniquePathNumber(base_store_path))); (*store_map)[id] = store_factory_->CreateV4Store(db_task_runner, store_path); }
diff --git a/chrome/browser/sessions/session_restore_browsertest.cc b/chrome/browser/sessions/session_restore_browsertest.cc index 37723c2..d0b53133 100644 --- a/chrome/browser/sessions/session_restore_browsertest.cc +++ b/chrome/browser/sessions/session_restore_browsertest.cc
@@ -288,6 +288,26 @@ "http://google.com/5", "http://google.com/6"}; +// Restore session with url passed in command line. +class SessionRestoreWithURLInCommandLineTest : public SessionRestoreTest { + public: + SessionRestoreWithURLInCommandLineTest() = default; + + protected: + void SetUpCommandLine(base::CommandLine* command_line) override { + SessionRestoreTest::SetUpCommandLine(command_line); + command_line_url_ = ui_test_utils::GetTestUrl( + base::FilePath(base::FilePath::kCurrentDirectory), + base::FilePath(FILE_PATH_LITERAL("title1.html"))); + command_line->AppendArg(command_line_url_.spec()); + } + + GURL command_line_url_; + + private: + DISALLOW_COPY_AND_ASSIGN(SessionRestoreWithURLInCommandLineTest); +}; + // Verifies that restored tabs have a root window. This is important // otherwise the wrong information is communicated to the renderer. // (http://crbug.com/342672). @@ -1827,3 +1847,34 @@ } } } + +IN_PROC_BROWSER_TEST_F(SessionRestoreWithURLInCommandLineTest, + PRE_TabWithURLFromCommandLineIsActive) { + SessionStartupPref pref(SessionStartupPref::DEFAULT); + SessionStartupPref::SetStartupPref(browser()->profile(), pref); + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + // Add 3 pinned tabs. + for (const auto& url : {url1_, url2_, url3_}) { + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + tab_strip_model->SetTabPinned(tab_strip_model->active_index(), true); + } + EXPECT_EQ(4, tab_strip_model->count()); + EXPECT_EQ(3, tab_strip_model->IndexOfFirstNonPinnedTab()); +} + +IN_PROC_BROWSER_TEST_F(SessionRestoreWithURLInCommandLineTest, + TabWithURLFromCommandLineIsActive) { + TabStripModel* tab_strip_model = browser()->tab_strip_model(); + EXPECT_EQ(4, tab_strip_model->count()); + EXPECT_EQ(3, tab_strip_model->active_index()); + EXPECT_EQ(command_line_url_, + tab_strip_model->GetActiveWebContents()->GetURL()); + + // Check that the all pinned tabs have been restored. + EXPECT_EQ(3, tab_strip_model->IndexOfFirstNonPinnedTab()); + EXPECT_EQ(url1_, tab_strip_model->GetWebContentsAt(0)->GetURL()); + EXPECT_EQ(url2_, tab_strip_model->GetWebContentsAt(1)->GetURL()); + EXPECT_EQ(url3_, tab_strip_model->GetWebContentsAt(2)->GetURL()); +}
diff --git a/chrome/browser/sharing/click_to_call/click_to_call_message_handler_android.cc b/chrome/browser/sharing/click_to_call/click_to_call_message_handler_android.cc index 68febfb..301e5397 100644 --- a/chrome/browser/sharing/click_to_call/click_to_call_message_handler_android.cc +++ b/chrome/browser/sharing/click_to_call/click_to_call_message_handler_android.cc
@@ -20,6 +20,6 @@ std::string phone_number = message.click_to_call_message().phone_number(); JNIEnv* env = base::android::AttachCurrentThread(); - Java_ClickToCallMessageHandler_showNotification( + Java_ClickToCallMessageHandler_handleMessage( env, base::android::ConvertUTF8ToJavaString(env, phone_number)); }
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index d9de7126..85e1f182 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -117,7 +117,7 @@ "interventions/intervention_delegate.h", "interventions/intervention_infobar_delegate.cc", "interventions/intervention_infobar_delegate.h", - "javascript_dialogs/chrome_javascript_native_dialog_factory.h", + "javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h", "javascript_dialogs/javascript_dialog.h", "javascript_dialogs/javascript_dialog_tab_helper.cc", "javascript_dialogs/javascript_dialog_tab_helper.h", @@ -950,8 +950,6 @@ "in_product_help/reopen_tab_in_product_help_trigger.h", "intent_picker_tab_helper.cc", "intent_picker_tab_helper.h", - "javascript_dialogs/javascript_dialog_views.cc", - "javascript_dialogs/javascript_dialog_views.h", "layout_constants.cc", "layout_constants.h", "location_bar/location_bar.cc", @@ -2733,6 +2731,8 @@ "views/frame/web_contents_close_handler.cc", "views/frame/web_contents_close_handler.h", "views/frame/web_contents_close_handler_delegate.h", + "views/front_eliding_title_label.cc", + "views/front_eliding_title_label.h", "views/fullscreen_control/fullscreen_control_host.cc", "views/fullscreen_control/fullscreen_control_host.h", "views/fullscreen_control/fullscreen_control_popup.cc", @@ -2767,6 +2767,8 @@ "views/infobars/infobar_container_view.h", "views/infobars/infobar_view.cc", "views/infobars/infobar_view.h", + "views/javascript_dialog_views.cc", + "views/javascript_dialog_views.h", "views/layout/interpolating_layout_manager.cc", "views/layout/interpolating_layout_manager.h", "views/load_complete_listener.cc", @@ -2967,8 +2969,6 @@ "views/permission_bubble/chooser_bubble_ui.cc", "views/permission_bubble/chooser_bubble_ui.h", "views/permission_bubble/chooser_bubble_ui_views.cc", - "views/permission_bubble/front_eliding_title_label.cc", - "views/permission_bubble/front_eliding_title_label.h", "views/permission_bubble/permission_prompt_impl.cc", "views/permission_bubble/permission_prompt_impl.h", "views/permission_bubble/permission_prompt_impl_views.cc",
diff --git a/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc b/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc index ac0e615..72cddef 100644 --- a/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc +++ b/chrome/browser/ui/android/javascript_app_modal_dialog_android.cc
@@ -11,7 +11,7 @@ #include "base/metrics/histogram_macros.h" #include "chrome/android/chrome_jni_headers/JavascriptAppModalDialog_jni.h" #include "chrome/browser/android/tab_android.h" -#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h" +#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h" #include "components/app_modal/app_modal_dialog_queue.h" #include "components/app_modal/javascript_app_modal_dialog.h" #include "components/app_modal/javascript_dialog_manager.h" @@ -194,8 +194,7 @@ } // namespace -void InstallChromeJavaScriptNativeDialogFactory() { +void InstallChromeJavaScriptNativeAppModalDialogFactory() { app_modal::JavaScriptDialogManager::GetInstance()->SetNativeDialogFactory( base::WrapUnique(new ChromeJavaScriptNativeDialogAndroidFactory)); } -
diff --git a/chrome/browser/ui/android/javascript_dialog_android.cc b/chrome/browser/ui/android/javascript_dialog_android.cc index 3b58230..d38187c 100644 --- a/chrome/browser/ui/android/javascript_dialog_android.cc +++ b/chrome/browser/ui/android/javascript_dialog_android.cc
@@ -6,6 +6,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" +#include "base/callback.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" #include "chrome/android/chrome_jni_headers/JavascriptTabModalDialog_jni.h" @@ -32,7 +33,8 @@ } } -base::WeakPtr<JavaScriptDialogAndroid> JavaScriptDialogAndroid::Create( +// static +base::WeakPtr<JavaScriptDialog> JavaScriptDialog::CreateNewDialog( content::WebContents* parent_web_contents, content::WebContents* alerting_web_contents, const base::string16& title,
diff --git a/chrome/browser/ui/android/javascript_dialog_android.h b/chrome/browser/ui/android/javascript_dialog_android.h index a3850cb..6852b97b 100644 --- a/chrome/browser/ui/android/javascript_dialog_android.h +++ b/chrome/browser/ui/android/javascript_dialog_android.h
@@ -50,6 +50,8 @@ jboolean button_clicked); private: + friend class JavaScriptDialog; + JavaScriptDialogAndroid(content::WebContents* parent_web_contents, content::WebContents* alerting_web_contents, const base::string16& title,
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm index 2357156..995cc415 100644 --- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -13,7 +13,7 @@ #include "base/memory/ptr_util.h" #import "chrome/browser/chrome_browser_application_mac.h" #include "chrome/browser/ui/blocked_content/popunder_preventer.h" -#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h" +#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h" #include "components/app_modal/javascript_app_modal_dialog.h" #include "components/app_modal/javascript_dialog_manager.h" #include "components/app_modal/javascript_native_dialog_factory.h" @@ -206,7 +206,7 @@ } // namespace -void InstallChromeJavaScriptNativeDialogFactory() { +void InstallChromeJavaScriptNativeAppModalDialogFactory() { app_modal::JavaScriptDialogManager::GetInstance()->SetNativeDialogFactory( base::WrapUnique(new ChromeJavaScriptNativeDialogCocoaFactory)); }
diff --git a/chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h b/chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h similarity index 68% rename from chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h rename to chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h index 4649679..6b45d10 100644 --- a/chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h +++ b/chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h
@@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_CHROME_JAVASCRIPT_NATIVE_DIALOG_FACTORY_H_ -#define CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_CHROME_JAVASCRIPT_NATIVE_DIALOG_FACTORY_H_ +#ifndef CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_CHROME_JAVASCRIPT_NATIVE_APP_MODAL_DIALOG_FACTORY_H_ +#define CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_CHROME_JAVASCRIPT_NATIVE_APP_MODAL_DIALOG_FACTORY_H_ -void InstallChromeJavaScriptNativeDialogFactory(); +void InstallChromeJavaScriptNativeAppModalDialogFactory(); -#endif // CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_CHROME_JAVASCRIPT_NATIVE_DIALOG_FACTORY_H_ - +#endif // CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_CHROME_JAVASCRIPT_NATIVE_APP_MODAL_DIALOG_FACTORY_H_
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog.h b/chrome/browser/ui/javascript_dialogs/javascript_dialog.h index dcbb007..ff0d662 100644 --- a/chrome/browser/ui/javascript_dialogs/javascript_dialog.h +++ b/chrome/browser/ui/javascript_dialogs/javascript_dialog.h
@@ -7,14 +7,31 @@ #include <memory> +#include "base/callback_forward.h" #include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" #include "build/build_config.h" #include "content/public/browser/javascript_dialog_manager.h" +namespace content { +class WebContents; +} + class JavaScriptDialog { public: virtual ~JavaScriptDialog() {} + // Factory function for creating a tab-modal Javascript dialog. + static base::WeakPtr<JavaScriptDialog> CreateNewDialog( + content::WebContents* parent_web_contents, + content::WebContents* alerting_web_contents, + const base::string16& title, + content::JavaScriptDialogType dialog_type, + const base::string16& message_text, + const base::string16& default_prompt_text, + content::JavaScriptDialogManager::DialogClosedCallback dialog_callback, + base::OnceClosure dialog_closed_callback); + // Closes the dialog without sending a callback. This is useful when the // JavaScriptDialogTabHelper needs to make this dialog go away so that it can // respond to a call that requires it to make no callback or make a customized
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.cc b/chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.cc index fc88cb8e..65e4c979 100644 --- a/chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.cc +++ b/chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.cc
@@ -11,6 +11,7 @@ #include "base/feature_list.h" #include "base/metrics/histogram_macros.h" #include "base/strings/stringprintf.h" +#include "chrome/browser/ui/javascript_dialogs/javascript_dialog.h" #include "chrome/browser/ui/tab_modal_confirm_dialog.h" #include "components/app_modal/javascript_dialog_manager.h" #include "components/navigation_metrics/navigation_metrics.h" @@ -31,7 +32,6 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" -#include "chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #endif @@ -138,28 +138,6 @@ HTTP_MAIN_FRAME_NON_HTTP_ALERTING_FRAME_DIFFERENT_ORIGIN_ANCESTOR; } -base::WeakPtr<JavaScriptDialog> CreateNewDialog( - content::WebContents* parent_web_contents, - content::WebContents* alerting_web_contents, - const base::string16& title, - content::JavaScriptDialogType dialog_type, - const base::string16& message_text, - const base::string16& default_prompt_text, - content::JavaScriptDialogManager::DialogClosedCallback dialog_callback, - base::OnceClosure dialog_closed_callback) { -#if defined(OS_ANDROID) - return JavaScriptDialogAndroid::Create( - parent_web_contents, alerting_web_contents, title, dialog_type, - message_text, default_prompt_text, std::move(dialog_callback), - std::move(dialog_closed_callback)); -#else - return JavaScriptDialogViews::Create( - parent_web_contents, alerting_web_contents, title, dialog_type, - message_text, default_prompt_text, std::move(dialog_callback), - std::move(dialog_closed_callback)); -#endif -} - } // namespace JavaScriptDialogTabHelper::JavaScriptDialogTabHelper( @@ -302,8 +280,9 @@ if (make_pending) { DCHECK(!dialog_); pending_dialog_ = base::BindOnce( - &CreateNewDialog, parent_web_contents, alerting_web_contents, title, - dialog_type, truncated_message_text, truncated_default_prompt_text, + &JavaScriptDialog::CreateNewDialog, parent_web_contents, + alerting_web_contents, title, dialog_type, truncated_message_text, + truncated_default_prompt_text, base::BindOnce(&JavaScriptDialogTabHelper::CloseDialog, base::Unretained(this), DismissalCause::kDialogButtonClicked), @@ -312,7 +291,7 @@ false, base::string16())); } else { DCHECK(!pending_dialog_); - dialog_ = CreateNewDialog( + dialog_ = JavaScriptDialog::CreateNewDialog( parent_web_contents, alerting_web_contents, title, dialog_type, truncated_message_text, truncated_default_prompt_text, base::BindOnce(&JavaScriptDialogTabHelper::CloseDialog,
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc index aa81ec45..9ca60ea0 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -708,51 +708,52 @@ // may be shown alongside command-line tabs. StartupTabs tabs = provider.GetResetTriggerTabs(profile_); - // Maybe add any tabs which the user has previously pinned. - AppendTabs(provider.GetPinnedTabs(command_line_, profile_), &tabs); - - // URLs passed on the command line supersede all others. + // URLs passed on the command line supersede all others, except pinned tabs. AppendTabs(cmd_line_tabs, &tabs); - if (!cmd_line_tabs.empty()) - return tabs; + if (cmd_line_tabs.empty()) { + // A Master Preferences file provided with this distribution may specify + // tabs to be displayed on first run, overriding all non-command-line tabs, + // including the profile reset tab. + StartupTabs distribution_tabs = + provider.GetDistributionFirstRunTabs(browser_creator_); + if (!distribution_tabs.empty()) + return distribution_tabs; - // A Master Preferences file provided with this distribution may specify - // tabs to be displayed on first run, overriding all non-command-line tabs, - // including the profile reset tab. - StartupTabs distribution_tabs = - provider.GetDistributionFirstRunTabs(browser_creator_); - if (!distribution_tabs.empty()) - return distribution_tabs; + StartupTabs onboarding_tabs; + if (promotional_tabs_enabled) { + // This is a launch from a prompt presented to an inactive user who chose + // to open Chrome and is being brought to a specific URL for this one + // launch. Launch the browser with the desired welcome back URL in the + // foreground and the other ordinary URLs (e.g., a restored session) in + // the background. + StartupTabs welcome_back_tabs = provider.GetWelcomeBackTabs( + profile_, browser_creator_, process_startup); + AppendTabs(welcome_back_tabs, &tabs); - StartupTabs onboarding_tabs; - if (promotional_tabs_enabled) { - // This is a launch from a prompt presented to an inactive user who chose to - // open Chrome and is being brought to a specific URL for this one launch. - // Launch the browser with the desired welcome back URL in the foreground - // and the other ordinary URLs (e.g., a restored session) in the background. - StartupTabs welcome_back_tabs = provider.GetWelcomeBackTabs( - profile_, browser_creator_, process_startup); - AppendTabs(welcome_back_tabs, &tabs); - - if (welcome_enabled) { - // Policies for welcome (e.g., first run) may show promotional and - // introductory content depending on a number of system status factors, - // including OS and whether or not this is First Run. - onboarding_tabs = provider.GetOnboardingTabs(profile_); - AppendTabs(onboarding_tabs, &tabs); + if (welcome_enabled) { + // Policies for welcome (e.g., first run) may show promotional and + // introductory content depending on a number of system status factors, + // including OS and whether or not this is First Run. + onboarding_tabs = provider.GetOnboardingTabs(profile_); + AppendTabs(onboarding_tabs, &tabs); + } } + + // If the user has set the preference indicating URLs to show on opening, + // read and add those. + StartupTabs prefs_tabs = + provider.GetPreferencesTabs(command_line_, profile_); + AppendTabs(prefs_tabs, &tabs); + + // Potentially add the New Tab Page. Onboarding content is designed to + // replace (and eventually funnel the user to) the NTP. Likewise, URLs + // from preferences are explicitly meant to override showing the NTP. + if (onboarding_tabs.empty() && prefs_tabs.empty()) + AppendTabs(provider.GetNewTabPageTabs(command_line_, profile_), &tabs); } - // If the user has set the preference indicating URLs to show on opening, - // read and add those. - StartupTabs prefs_tabs = provider.GetPreferencesTabs(command_line_, profile_); - AppendTabs(prefs_tabs, &tabs); - - // Potentially add the New Tab Page. Onboarding content is designed to - // replace (and eventually funnel the user to) the NTP. Likewise, URLs - // from preferences are explicitly meant to override showing the NTP. - if (onboarding_tabs.empty() && prefs_tabs.empty()) - AppendTabs(provider.GetNewTabPageTabs(command_line_, profile_), &tabs); + // Maybe add any tabs which the user has previously pinned. + AppendTabs(provider.GetPinnedTabs(command_line_, profile_), &tabs); return tabs; }
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc b/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc index a9cc67f..9fa5a4d 100644 --- a/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc +++ b/chrome/browser/ui/startup/startup_browser_creator_impl_unittest.cc
@@ -113,25 +113,25 @@ provider, StartupTabs(), true, false, false, false, true, true); ASSERT_EQ(4U, output.size()); EXPECT_EQ("reset-trigger", output[0].url.host()); - EXPECT_EQ("pinned", output[1].url.host()); - EXPECT_EQ("onboarding", output[2].url.host()); - EXPECT_EQ("prefs", output[3].url.host()); + EXPECT_EQ("onboarding", output[1].url.host()); + EXPECT_EQ("prefs", output[2].url.host()); + EXPECT_EQ("pinned", output[3].url.host()); // No extra onboarding content for managed starts. output = impl.DetermineStartupTabs(provider, StartupTabs(), true, false, false, false, false, true); ASSERT_EQ(3U, output.size()); EXPECT_EQ("reset-trigger", output[0].url.host()); - EXPECT_EQ("pinned", output[1].url.host()); - EXPECT_EQ("prefs", output[2].url.host()); + EXPECT_EQ("prefs", output[1].url.host()); + EXPECT_EQ("pinned", output[2].url.host()); // No onboarding if not enabled even if promo is allowed. output = impl.DetermineStartupTabs(provider, StartupTabs(), true, false, false, false, true, false); ASSERT_EQ(3U, output.size()); EXPECT_EQ("reset-trigger", output[0].url.host()); - EXPECT_EQ("pinned", output[1].url.host()); - EXPECT_EQ("prefs", output[2].url.host()); + EXPECT_EQ("prefs", output[1].url.host()); + EXPECT_EQ("pinned", output[2].url.host()); } // Only the New Tab Page should appear in Incognito mode, skipping all the usual @@ -211,8 +211,8 @@ provider, cmd_line_tabs, true, false, false, false, true, true); ASSERT_EQ(3U, output.size()); EXPECT_EQ("reset-trigger", output[0].url.host()); - EXPECT_EQ("pinned", output[1].url.host()); - EXPECT_EQ("cmd-line", output[2].url.host()); + EXPECT_EQ("cmd-line", output[1].url.host()); + EXPECT_EQ("pinned", output[2].url.host()); // Also test that both incognito and crash recovery don't interfere with // command line tabs. @@ -250,8 +250,8 @@ false, false, true, true); ASSERT_EQ(3U, output.size()); EXPECT_EQ("reset-trigger", output[0].url.host()); - EXPECT_EQ("pinned", output[1].url.host()); - EXPECT_EQ("new-tab", output[2].url.host()); + EXPECT_EQ("new-tab", output[1].url.host()); + EXPECT_EQ("pinned", output[2].url.host()); } // The welcome back page should appear before any other session restore tabs. @@ -266,23 +266,23 @@ impl.DetermineStartupTabs(provider_allows_ntp, StartupTabs(), true, false, false, false, true, true); ASSERT_EQ(3U, output.size()); - EXPECT_EQ("pinned", output[0].url.host()); - EXPECT_EQ("welcome-back", output[1].url.host()); - EXPECT_EQ("prefs", output[2].url.host()); + EXPECT_EQ("welcome-back", output[0].url.host()); + EXPECT_EQ("prefs", output[1].url.host()); + EXPECT_EQ("pinned", output[2].url.host()); // No welcome back for non-startup opens. output = impl.DetermineStartupTabs(provider_allows_ntp, StartupTabs(), false, false, false, false, true, true); ASSERT_EQ(2U, output.size()); - EXPECT_EQ("pinned", output[0].url.host()); - EXPECT_EQ("prefs", output[1].url.host()); + EXPECT_EQ("prefs", output[0].url.host()); + EXPECT_EQ("pinned", output[1].url.host()); // No welcome back for managed starts even if first run. output = impl.DetermineStartupTabs(provider_allows_ntp, StartupTabs(), true, false, false, false, false, true); ASSERT_EQ(2U, output.size()); - EXPECT_EQ("pinned", output[0].url.host()); - EXPECT_EQ("prefs", output[1].url.host()); + EXPECT_EQ("prefs", output[0].url.host()); + EXPECT_EQ("pinned", output[1].url.host()); } TEST(StartupBrowserCreatorImplTest, DetermineBrowserOpenBehavior_Startup) {
diff --git a/chrome/browser/ui/ui_features.cc b/chrome/browser/ui/ui_features.cc index be27ca2..440dee7 100644 --- a/chrome/browser/ui/ui_features.cc +++ b/chrome/browser/ui/ui_features.cc
@@ -45,7 +45,7 @@ // Enables popup cards containing tab information when hovering over a tab. // https://crbug.com/910739 const base::Feature kTabHoverCards{"TabHoverCards", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // Parameter name used for tab hover cards user study. // TODO(corising): Removed this after tab hover cards user study. const char kTabHoverCardsFeatureParameterName[] = "setting";
diff --git a/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc b/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc index e16c846..86fdf20 100644 --- a/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc +++ b/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h" +#include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_app_modal_dialog_factory.h" #include "base/macros.h" #include "base/memory/ptr_util.h" @@ -80,7 +80,7 @@ } // namespace -void InstallChromeJavaScriptNativeDialogFactory() { +void InstallChromeJavaScriptNativeAppModalDialogFactory() { app_modal::JavaScriptDialogManager::GetInstance()->SetNativeDialogFactory( base::WrapUnique(new ChromeJavaScriptNativeDialogViewsFactory)); }
diff --git a/chrome/browser/ui/views/permission_bubble/front_eliding_title_label.cc b/chrome/browser/ui/views/front_eliding_title_label.cc similarity index 89% rename from chrome/browser/ui/views/permission_bubble/front_eliding_title_label.cc rename to chrome/browser/ui/views/front_eliding_title_label.cc index 662e7b9..20ddd842 100644 --- a/chrome/browser/ui/views/permission_bubble/front_eliding_title_label.cc +++ b/chrome/browser/ui/views/front_eliding_title_label.cc
@@ -2,11 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/views/permission_bubble/front_eliding_title_label.h" +#include "chrome/browser/ui/views/front_eliding_title_label.h" #include "ui/views/accessibility/view_accessibility.h" -std::unique_ptr<views::Label> ConstructFrontElidingTitleLabel( +std::unique_ptr<views::Label> CreateFrontElidingTitleLabel( const base::string16& text) { auto label = std::make_unique<views::Label>(text, views::style::CONTEXT_DIALOG_TITLE);
diff --git a/chrome/browser/ui/views/front_eliding_title_label.h b/chrome/browser/ui/views/front_eliding_title_label.h new file mode 100644 index 0000000..1795c98b --- /dev/null +++ b/chrome/browser/ui/views/front_eliding_title_label.h
@@ -0,0 +1,21 @@ +// 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_UI_VIEWS_FRONT_ELIDING_TITLE_LABEL_H_ +#define CHROME_BROWSER_UI_VIEWS_FRONT_ELIDING_TITLE_LABEL_H_ + +#include <memory> + +#include "ui/views/controls/label.h" + +// Creates a new label to be used for dialog titles that contain an origin that +// need to be elided from the front. The label will also ignored by screen +// readers (since the bubbles handle the context). +// TODO(crbug.com/987715): For now this is a simplistic implementation that +// elides the entire string from the front, which works well for English strings +// that start with the origin, but not so well for other languages. +std::unique_ptr<views::Label> CreateFrontElidingTitleLabel( + const base::string16& text); + +#endif // CHROME_BROWSER_UI_VIEWS_FRONT_ELIDING_TITLE_LABEL_H_
diff --git a/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc b/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc new file mode 100644 index 0000000..b607cf7 --- /dev/null +++ b/chrome/browser/ui/views/hung_plugin_tab_helper_unittest.cc
@@ -0,0 +1,125 @@ +// 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 "chrome/browser/ui/hung_plugin_tab_helper.h" + +#include "base/scoped_observer.h" +#include "chrome/browser/infobars/infobar_service.h" +#include "chrome/browser/ui/views/infobars/confirm_infobar.h" +#include "chrome/test/base/chrome_render_view_host_test_harness.h" +#include "chrome/test/views/chrome_test_views_delegate.h" +#include "ui/events/event.h" + +class HungPluginInfoBarObserver : public infobars::InfoBarManager::Observer { + public: + explicit HungPluginInfoBarObserver(infobars::InfoBarManager* manager); + + // infobars::InfoBarManager::Observer: + void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override; + + bool seen_removal() const { return seen_removal_; } + + private: + bool seen_removal_ = false; + + ScopedObserver<infobars::InfoBarManager, infobars::InfoBarManager::Observer> + infobar_observer_{this}; +}; + +HungPluginInfoBarObserver::HungPluginInfoBarObserver( + infobars::InfoBarManager* manager) { + infobar_observer_.Add(manager); +} + +void HungPluginInfoBarObserver::OnInfoBarRemoved(infobars::InfoBar* infobar, + bool animate) { + seen_removal_ = true; +} + +class HungPluginMockInfoBar : public ConfirmInfoBar { + public: + explicit HungPluginMockInfoBar( + std::unique_ptr<ConfirmInfoBarDelegate> delegate); + + private: + // ConfirmInfoBar: + void ButtonPressed(views::Button* sender, const ui::Event& event) override; +}; + +HungPluginMockInfoBar::HungPluginMockInfoBar( + std::unique_ptr<ConfirmInfoBarDelegate> delegate) + : ConfirmInfoBar(std::move(delegate)) {} + +void HungPluginMockInfoBar::ButtonPressed(views::Button* sender, + const ui::Event& event) { + DCHECK(owner()); + HungPluginInfoBarObserver observer(owner()); + if (GetDelegate()->Accept()) { + ASSERT_FALSE(observer.seen_removal()); + RemoveSelf(); + } +} + +class HungPluginMockInfoBarService : public InfoBarService { + public: + // Creates a HungPluginMockInfoBarService and attaches it as the + // InfoBarService for |web_contents|. + static void CreateForWebContents(content::WebContents* web_contents); + + std::unique_ptr<infobars::InfoBar> CreateConfirmInfoBar( + std::unique_ptr<ConfirmInfoBarDelegate> delegate) override; + + private: + using InfoBarService::InfoBarService; +}; + +void HungPluginMockInfoBarService::CreateForWebContents( + content::WebContents* web_contents) { + DCHECK(web_contents); + const void* user_data_key = UserDataKey(); + DCHECK(!web_contents->GetUserData(user_data_key)); + web_contents->SetUserData( + user_data_key, + base::WrapUnique(new HungPluginMockInfoBarService(web_contents))); +} + +std::unique_ptr<infobars::InfoBar> +HungPluginMockInfoBarService::CreateConfirmInfoBar( + std::unique_ptr<ConfirmInfoBarDelegate> delegate) { + return std::make_unique<HungPluginMockInfoBar>(std::move(delegate)); +} + +class HungPluginTabHelperTest : public ChromeRenderViewHostTestHarness { + public: + void SetUp() override; + + private: + ChromeTestViewsDelegate views_delegate_; +}; + +void HungPluginTabHelperTest::SetUp() { + ChromeRenderViewHostTestHarness::SetUp(); + + HungPluginTabHelper::CreateForWebContents(web_contents()); + HungPluginMockInfoBarService::CreateForWebContents(web_contents()); +} + +class DummyEvent : public ui::Event { + public: + DummyEvent(); +}; + +DummyEvent::DummyEvent() : Event(ui::ET_UNKNOWN, base::TimeTicks(), 0) {} + +// Regression test for https://crbug.com/969099 . +TEST_F(HungPluginTabHelperTest, DontRemoveTwice) { + HungPluginTabHelper::FromWebContents(web_contents()) + ->PluginHungStatusChanged(0, base::FilePath(), true); + InfoBarService* infobar_service = + InfoBarService::FromWebContents(web_contents()); + ASSERT_EQ(1u, infobar_service->infobar_count()); + static_cast<InfoBarView*>(infobar_service->infobar_at(0)) + ->ButtonPressed(nullptr, DummyEvent()); + EXPECT_EQ(0u, infobar_service->infobar_count()); +}
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.cc b/chrome/browser/ui/views/infobars/confirm_infobar.cc index 40598dfd..35638b7 100644 --- a/chrome/browser/ui/views/infobars/confirm_infobar.cc +++ b/chrome/browser/ui/views/infobars/confirm_infobar.cc
@@ -109,11 +109,6 @@ } } -int ConfirmInfoBar::ContentMinimumWidth() const { - return label_->GetMinimumSize().width() + link_->GetMinimumSize().width() + - NonLabelWidth(); -} - void ConfirmInfoBar::LinkClicked(views::Link* source, int event_flags) { if (!owner()) return; // We're closing; don't call anything, it might access the owner. @@ -122,6 +117,11 @@ RemoveSelf(); } +int ConfirmInfoBar::ContentMinimumWidth() const { + return label_->GetMinimumSize().width() + link_->GetMinimumSize().width() + + NonLabelWidth(); +} + ConfirmInfoBarDelegate* ConfirmInfoBar::GetDelegate() { return delegate()->AsConfirmInfoBarDelegate(); }
diff --git a/chrome/browser/ui/views/infobars/confirm_infobar.h b/chrome/browser/ui/views/infobars/confirm_infobar.h index e590b71..81c268c 100644 --- a/chrome/browser/ui/views/infobars/confirm_infobar.h +++ b/chrome/browser/ui/views/infobars/confirm_infobar.h
@@ -28,17 +28,20 @@ explicit ConfirmInfoBar(std::unique_ptr<ConfirmInfoBarDelegate> delegate); ~ConfirmInfoBar() override; - private: // InfoBarView: void Layout() override; void ButtonPressed(views::Button* sender, const ui::Event& event) override; - int ContentMinimumWidth() const override; // views::LinkListener: void LinkClicked(views::Link* source, int event_flags) override; + protected: + // InfoBarView: + int ContentMinimumWidth() const override; + ConfirmInfoBarDelegate* GetDelegate(); + private: // Creates a button suitable for use as either OK or Cancel. views::MdTextButton* CreateButton(ConfirmInfoBarDelegate::InfoBarButton type);
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog_views.cc b/chrome/browser/ui/views/javascript_dialog_views.cc similarity index 83% rename from chrome/browser/ui/javascript_dialogs/javascript_dialog_views.cc rename to chrome/browser/ui/views/javascript_dialog_views.cc index 017df66..54d1c808d 100644 --- a/chrome/browser/ui/javascript_dialogs/javascript_dialog_views.cc +++ b/chrome/browser/ui/views/javascript_dialog_views.cc
@@ -2,17 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h" +#include "chrome/browser/ui/views/javascript_dialog_views.h" #include "chrome/browser/ui/browser_dialogs.h" +#include "chrome/browser/ui/views/front_eliding_title_label.h" #include "components/constrained_window/constrained_window_views.h" +#include "content/public/browser/javascript_dialog_manager.h" +#include "ui/views/bubble/bubble_frame_view.h" +#include "ui/views/controls/label.h" #include "ui/views/controls/message_box_view.h" #include "ui/views/controls/textfield/textfield.h" +#include "ui/views/layout/fill_layout.h" JavaScriptDialogViews::~JavaScriptDialogViews() = default; // static -base::WeakPtr<JavaScriptDialogViews> JavaScriptDialogViews::Create( +base::WeakPtr<JavaScriptDialog> JavaScriptDialog::CreateNewDialog( content::WebContents* parent_web_contents, content::WebContents* alerting_web_contents, const base::string16& title, @@ -69,35 +74,26 @@ return true; } -void JavaScriptDialogViews::DeleteDelegate() { - delete this; -} - bool JavaScriptDialogViews::ShouldShowCloseButton() const { return false; } -views::View* JavaScriptDialogViews::GetContentsView() { - return message_box_view_; -} - views::View* JavaScriptDialogViews::GetInitiallyFocusedView() { auto* text_box = message_box_view_->text_box(); return text_box ? text_box : views::DialogDelegate::GetInitiallyFocusedView(); } -views::Widget* JavaScriptDialogViews::GetWidget() { - return message_box_view_->GetWidget(); -} - -const views::Widget* JavaScriptDialogViews::GetWidget() const { - return message_box_view_->GetWidget(); -} - ui::ModalType JavaScriptDialogViews::GetModalType() const { return ui::MODAL_TYPE_CHILD; } +void JavaScriptDialogViews::AddedToWidget() { + auto* bubble_frame_view = static_cast<views::BubbleFrameView*>( + GetWidget()->non_client_view()->frame_view()); + bubble_frame_view->SetTitleView( + CreateFrontElidingTitleLabel(GetWindowTitle())); +} + JavaScriptDialogViews::JavaScriptDialogViews( content::WebContents* parent_web_contents, content::WebContents* alerting_web_contents, @@ -123,6 +119,9 @@ message_box_view_ = new views::MessageBoxView(params); DCHECK(message_box_view_); + SetLayoutManager(std::make_unique<views::FillLayout>()); + AddChildView(message_box_view_); + constrained_window::ShowWebModalDialogViews(this, parent_web_contents); chrome::RecordDialogCreation(chrome::DialogIdentifier::JAVA_SCRIPT); }
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h b/chrome/browser/ui/views/javascript_dialog_views.h similarity index 86% rename from chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h rename to chrome/browser/ui/views/javascript_dialog_views.h index ea463ac..7e92add 100644 --- a/chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h +++ b/chrome/browser/ui/views/javascript_dialog_views.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_DIALOG_VIEWS_H_ -#define CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_DIALOG_VIEWS_H_ +#ifndef CHROME_BROWSER_UI_VIEWS_JAVASCRIPT_DIALOG_VIEWS_H_ +#define CHROME_BROWSER_UI_VIEWS_JAVASCRIPT_DIALOG_VIEWS_H_ #include <memory> @@ -20,7 +20,7 @@ // when the user switches away to a different tab, used for WebContentses that // are browser tabs. class JavaScriptDialogViews : public JavaScriptDialog, - public views::DialogDelegate { + public views::DialogDelegateView { public: ~JavaScriptDialogViews() override; @@ -48,17 +48,18 @@ bool Cancel() override; bool Accept() override; bool Close() override; - void DeleteDelegate() override; // views::WidgetDelegate: bool ShouldShowCloseButton() const override; - views::View* GetContentsView() override; views::View* GetInitiallyFocusedView() override; - views::Widget* GetWidget() override; - const views::Widget* GetWidget() const override; ui::ModalType GetModalType() const override; + // views::View: + void AddedToWidget() override; + private: + friend class JavaScriptDialog; + JavaScriptDialogViews( content::WebContents* parent_web_contents, content::WebContents* alerting_web_contents, @@ -84,4 +85,4 @@ DISALLOW_COPY_AND_ASSIGN(JavaScriptDialogViews); }; -#endif // CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_DIALOG_VIEWS_H_ +#endif // CHROME_BROWSER_UI_VIEWS_JAVASCRIPT_DIALOG_VIEWS_H_
diff --git a/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui.cc b/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui.cc index e97cfbc5..65e4bdba 100644 --- a/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui.cc +++ b/chrome/browser/ui/views/permission_bubble/chooser_bubble_ui.cc
@@ -10,7 +10,7 @@ #include "chrome/browser/ui/permission_bubble/chooser_bubble_delegate.h" #include "chrome/browser/ui/views/bubble_anchor_util_views.h" #include "chrome/browser/ui/views/device_chooser_content_view.h" -#include "chrome/browser/ui/views/permission_bubble/front_eliding_title_label.h" +#include "chrome/browser/ui/views/front_eliding_title_label.h" #include "components/bubble/bubble_controller.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_frame_view.h" @@ -108,7 +108,7 @@ void ChooserBubbleUiViewDelegate::AddedToWidget() { GetBubbleFrameView()->SetTitleView( - ConstructFrontElidingTitleLabel(GetWindowTitle())); + CreateFrontElidingTitleLabel(GetWindowTitle())); } base::string16 ChooserBubbleUiViewDelegate::GetWindowTitle() const {
diff --git a/chrome/browser/ui/views/permission_bubble/front_eliding_title_label.h b/chrome/browser/ui/views/permission_bubble/front_eliding_title_label.h deleted file mode 100644 index 84f22f9b..0000000 --- a/chrome/browser/ui/views/permission_bubble/front_eliding_title_label.h +++ /dev/null
@@ -1,18 +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. - -#ifndef CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_FRONT_ELIDING_TITLE_LABEL_H_ -#define CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_FRONT_ELIDING_TITLE_LABEL_H_ - -#include <memory> - -#include "ui/views/controls/label.h" - -// Constructs a custom title label for permission and chooser bubbles that takes -// care of eliding the origin from the left, and configures itself to be -// ignored by screen readers (since the bubbles handle the context). -std::unique_ptr<views::Label> ConstructFrontElidingTitleLabel( - const base::string16& text); - -#endif // CHROME_BROWSER_UI_VIEWS_PERMISSION_BUBBLE_FRONT_ELIDING_TITLE_LABEL_H_
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc index 63af5ca..27d921ed 100644 --- a/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc +++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_impl.cc
@@ -17,9 +17,9 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/views/bubble_anchor_util_views.h" #include "chrome/browser/ui/views/chrome_layout_provider.h" +#include "chrome/browser/ui/views/front_eliding_title_label.h" #include "chrome/browser/ui/views/page_info/permission_selector_row.h" #include "chrome/browser/ui/views/page_info/permission_selector_row_observer.h" -#include "chrome/browser/ui/views/permission_bubble/front_eliding_title_label.h" #include "chrome/grit/generated_resources.h" #include "components/strings/grit/components_strings.h" #include "ui/base/l10n/l10n_util.h" @@ -151,7 +151,7 @@ return; GetBubbleFrameView()->SetTitleView( - ConstructFrontElidingTitleLabel(GetWindowTitle())); + CreateFrontElidingTitleLabel(GetWindowTitle())); } bool PermissionsBubbleDialogDelegateView::ShouldShowCloseButton() const {
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc index b59debc..70ed62f1 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view.cc +++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -222,140 +222,190 @@ void ProfileMenuView::ButtonPressed(views::Button* sender, const ui::Event& event) { if (sender == manage_google_account_button_) { - DCHECK(!dice_accounts_.empty()); - base::RecordAction( - base::UserMetricsAction("ProfileChooser_ManageGoogleAccountClicked")); - NavigateToGoogleAccountPage(browser()->profile(), dice_accounts_[0].email); + OnManageGoogleAccountButtonClicked(); } else if (sender == passwords_button_) { - base::RecordAction( - base::UserMetricsAction("ProfileChooser_PasswordsClicked")); - NavigateToManagePasswordsPage( - browser(), password_manager::ManagePasswordsReferrer::kProfileChooser); + OnPasswordsButtonClicked(); } else if (sender == credit_cards_button_) { - base::RecordAction( - base::UserMetricsAction("ProfileChooser_PaymentsClicked")); - chrome::ShowSettingsSubPage(browser(), chrome::kPaymentsSubPage); + OnCreditCardsButtonClicked(); } else if (sender == addresses_button_) { - base::RecordAction( - base::UserMetricsAction("ProfileChooser_AddressesClicked")); - chrome::ShowSettingsSubPage(browser(), chrome::kAddressesSubPage); + OnAddressesButtonClicked(); } else if (sender == guest_profile_button_) { - PrefService* service = g_browser_process->local_state(); - DCHECK(service); - DCHECK(service->GetBoolean(prefs::kBrowserGuestModeEnabled)); - profiles::SwitchToGuestProfile(ProfileManager::CreateCallback()); - base::RecordAction(base::UserMetricsAction("ProfileChooser_GuestClicked")); + OnGuestProfileButtonClicked(); } else if (sender == users_button_) { - // If this is a guest session, close all the guest browser windows. - if (browser()->profile()->IsGuestSession()) { - profiles::CloseGuestProfileWindows(); - } else { - base::RecordAction( - base::UserMetricsAction("ProfileChooser_ManageClicked")); - UserManager::Show(base::FilePath(), - profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); - } - PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER); + OnManageProfilesButtonClicked(); } else if (sender == lock_button_) { - profiles::LockProfile(browser()->profile()); - PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK); + OnLockButtonClicked(); } else if (sender == close_all_windows_button_) { - profiles::CloseProfileWindows(browser()->profile()); - base::RecordAction( - base::UserMetricsAction("ProfileChooser_CloseAllClicked")); + OnExitProfileButtonClicked(); } else if (sender == sync_error_button_) { sync_ui_util::AvatarSyncErrorType error = static_cast<sync_ui_util::AvatarSyncErrorType>(sender->GetID()); - switch (error) { - case sync_ui_util::MANAGED_USER_UNRECOVERABLE_ERROR: - chrome::ShowSettingsSubPage(browser(), chrome::kSignOutSubPage); - break; - case sync_ui_util::UNRECOVERABLE_ERROR: - if (ProfileSyncServiceFactory::GetForProfile(browser()->profile())) { - syncer::RecordSyncEvent(syncer::STOP_FROM_OPTIONS); - } - - // GetPrimaryAccountMutator() might return nullptr on some platforms. - if (auto* account_mutator = - IdentityManagerFactory::GetForProfile(browser()->profile()) - ->GetPrimaryAccountMutator()) { - account_mutator->ClearPrimaryAccount( - signin::PrimaryAccountMutator::ClearAccountsAction::kDefault, - signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, - signin_metrics::SignoutDelete::IGNORE_METRIC); - Hide(); - browser()->signin_view_controller()->ShowSignin( - profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_); - } - break; - case sync_ui_util::AUTH_ERROR: - Hide(); - browser()->signin_view_controller()->ShowSignin( - profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, browser(), access_point_); - break; - case sync_ui_util::UPGRADE_CLIENT_ERROR: - chrome::OpenUpdateChromeDialog(browser()); - break; - case sync_ui_util::PASSPHRASE_ERROR: - case sync_ui_util::SETTINGS_UNCONFIRMED_ERROR: - chrome::ShowSettingsSubPage(browser(), chrome::kSyncSetupSubPage); - break; - case sync_ui_util::NO_SYNC_ERROR: - NOTREACHED(); - break; - } - base::RecordAction( - base::UserMetricsAction("ProfileChooser_SignInAgainClicked")); + OnSyncErrorButtonClicked(error); } else if (sender == current_profile_card_) { - if (dice_enabled_ && - IdentityManagerFactory::GetForProfile(browser()->profile()) - ->HasPrimaryAccount()) { - chrome::ShowSettingsSubPage(browser(), chrome::kPeopleSubPage); - } else { - // Open settings to edit profile name and image. The profile doesn't need - // to be authenticated to open this. - avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); - PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE); - PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME); - } + OnCurrentProfileCardClicked(); } else if (sender == signin_current_profile_button_) { - Hide(); - browser()->signin_view_controller()->ShowSignin( - profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_); + OnSigninButtonClicked(); } else if (sender == signin_with_gaia_account_button_) { - DCHECK(dice_signin_button_view_->account()); - Hide(); - signin_ui_util::EnableSyncFromPromo( - browser(), dice_signin_button_view_->account().value(), access_point_, - true /* is_default_promo_account */); + OnSigninAccountButtonClicked(); } else if (sender == signout_button_) { - Hide(); - - // Sign out from all accounts. - IdentityManagerFactory::GetForProfile(browser()->profile()) - ->GetAccountsMutator() - ->RemoveAllAccounts(signin_metrics::SourceForRefreshTokenOperation:: - kUserMenu_SignOutAllAccounts); - base::RecordAction(base::UserMetricsAction("Signin_Signout_FromUserMenu")); + OnSignoutButtonClicked(); } else { // Either one of the "other profiles", or one of the profile accounts // buttons was pressed. ButtonIndexes::const_iterator profile_match = open_other_profile_indexes_map_.find(sender); if (profile_match != open_other_profile_indexes_map_.end()) { - avatar_menu_->SwitchToProfile( - profile_match->second, ui::DispositionFromEventFlags(event.flags()) == - WindowOpenDisposition::NEW_WINDOW, - ProfileMetrics::SWITCH_PROFILE_ICON); - base::RecordAction( - base::UserMetricsAction("ProfileChooser_ProfileClicked")); - Hide(); + OnOtherProfileButtonClicked(profile_match->second); } else { NOTREACHED(); } } } +void ProfileMenuView::OnManageGoogleAccountButtonClicked() { + base::RecordAction( + base::UserMetricsAction("ProfileChooser_ManageGoogleAccountClicked")); + DCHECK(!dice_accounts_.empty()); + NavigateToGoogleAccountPage(browser()->profile(), dice_accounts_[0].email); +} + +void ProfileMenuView::OnPasswordsButtonClicked() { + base::RecordAction( + base::UserMetricsAction("ProfileChooser_PasswordsClicked")); + NavigateToManagePasswordsPage( + browser(), password_manager::ManagePasswordsReferrer::kProfileChooser); +} + +void ProfileMenuView::OnCreditCardsButtonClicked() { + base::RecordAction(base::UserMetricsAction("ProfileChooser_PaymentsClicked")); + chrome::ShowSettingsSubPage(browser(), chrome::kPaymentsSubPage); +} + +void ProfileMenuView::OnAddressesButtonClicked() { + base::RecordAction( + base::UserMetricsAction("ProfileChooser_AddressesClicked")); + chrome::ShowSettingsSubPage(browser(), chrome::kAddressesSubPage); +} + +void ProfileMenuView::OnGuestProfileButtonClicked() { + base::RecordAction(base::UserMetricsAction("ProfileChooser_GuestClicked")); + PrefService* service = g_browser_process->local_state(); + DCHECK(service); + DCHECK(service->GetBoolean(prefs::kBrowserGuestModeEnabled)); + profiles::SwitchToGuestProfile(ProfileManager::CreateCallback()); +} + +void ProfileMenuView::OnManageProfilesButtonClicked() { + // If this is a guest session, close all the guest browser windows. + if (browser()->profile()->IsGuestSession()) { + profiles::CloseGuestProfileWindows(); + } else { + base::RecordAction(base::UserMetricsAction("ProfileChooser_ManageClicked")); + UserManager::Show(base::FilePath(), + profiles::USER_MANAGER_SELECT_PROFILE_NO_ACTION); + } + PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_OPEN_USER_MANAGER); +} + +void ProfileMenuView::OnLockButtonClicked() { + profiles::LockProfile(browser()->profile()); + PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK); +} + +void ProfileMenuView::OnExitProfileButtonClicked() { + base::RecordAction(base::UserMetricsAction("ProfileChooser_CloseAllClicked")); + profiles::CloseProfileWindows(browser()->profile()); +} + +void ProfileMenuView::OnSyncErrorButtonClicked( + sync_ui_util::AvatarSyncErrorType error) { + base::RecordAction( + base::UserMetricsAction("ProfileChooser_SignInAgainClicked")); + switch (error) { + case sync_ui_util::MANAGED_USER_UNRECOVERABLE_ERROR: + chrome::ShowSettingsSubPage(browser(), chrome::kSignOutSubPage); + break; + case sync_ui_util::UNRECOVERABLE_ERROR: + if (ProfileSyncServiceFactory::GetForProfile(browser()->profile())) { + syncer::RecordSyncEvent(syncer::STOP_FROM_OPTIONS); + } + + // GetPrimaryAccountMutator() might return nullptr on some platforms. + if (auto* account_mutator = + IdentityManagerFactory::GetForProfile(browser()->profile()) + ->GetPrimaryAccountMutator()) { + account_mutator->ClearPrimaryAccount( + signin::PrimaryAccountMutator::ClearAccountsAction::kDefault, + signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, + signin_metrics::SignoutDelete::IGNORE_METRIC); + Hide(); + browser()->signin_view_controller()->ShowSignin( + profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_); + } + break; + case sync_ui_util::AUTH_ERROR: + Hide(); + browser()->signin_view_controller()->ShowSignin( + profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH, browser(), access_point_); + break; + case sync_ui_util::UPGRADE_CLIENT_ERROR: + chrome::OpenUpdateChromeDialog(browser()); + break; + case sync_ui_util::PASSPHRASE_ERROR: + case sync_ui_util::SETTINGS_UNCONFIRMED_ERROR: + chrome::ShowSettingsSubPage(browser(), chrome::kSyncSetupSubPage); + break; + case sync_ui_util::NO_SYNC_ERROR: + NOTREACHED(); + break; + } +} + +void ProfileMenuView::OnCurrentProfileCardClicked() { + if (dice_enabled_ && + IdentityManagerFactory::GetForProfile(browser()->profile()) + ->HasPrimaryAccount()) { + chrome::ShowSettingsSubPage(browser(), chrome::kPeopleSubPage); + } else { + // Open settings to edit profile name and image. The profile doesn't need + // to be authenticated to open this. + avatar_menu_->EditProfile(avatar_menu_->GetActiveProfileIndex()); + PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_IMAGE); + PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_EDIT_NAME); + } +} + +void ProfileMenuView::OnSigninButtonClicked() { + Hide(); + browser()->signin_view_controller()->ShowSignin( + profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN, browser(), access_point_); +} + +void ProfileMenuView::OnSigninAccountButtonClicked() { + DCHECK(dice_signin_button_view_->account()); + Hide(); + signin_ui_util::EnableSyncFromPromo( + browser(), dice_signin_button_view_->account().value(), access_point_, + true /* is_default_promo_account */); +} + +void ProfileMenuView::OnSignoutButtonClicked() { + base::RecordAction(base::UserMetricsAction("Signin_Signout_FromUserMenu")); + Hide(); + // Sign out from all accounts. + IdentityManagerFactory::GetForProfile(browser()->profile()) + ->GetAccountsMutator() + ->RemoveAllAccounts(signin_metrics::SourceForRefreshTokenOperation:: + kUserMenu_SignOutAllAccounts); +} + +void ProfileMenuView::OnOtherProfileButtonClicked(int profile_index) { + base::RecordAction(base::UserMetricsAction("ProfileChooser_ProfileClicked")); + avatar_menu_->SwitchToProfile(profile_index, /*always_create=*/false, + ProfileMetrics::SWITCH_PROFILE_ICON); + Hide(); +} + void ProfileMenuView::StyledLabelLinkClicked(views::StyledLabel* label, const gfx::Range& range, int event_flags) {
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.h b/chrome/browser/ui/views/profiles/profile_menu_view.h index 32f2986..bbb5cbf 100644 --- a/chrome/browser/ui/views/profiles/profile_menu_view.h +++ b/chrome/browser/ui/views/profiles/profile_menu_view.h
@@ -57,6 +57,22 @@ // views::ButtonListener: void ButtonPressed(views::Button* sender, const ui::Event& event) override; + // Button actions. + void OnManageGoogleAccountButtonClicked(); + void OnPasswordsButtonClicked(); + void OnCreditCardsButtonClicked(); + void OnAddressesButtonClicked(); + void OnGuestProfileButtonClicked(); + void OnManageProfilesButtonClicked(); + void OnLockButtonClicked(); + void OnExitProfileButtonClicked(); + void OnSyncErrorButtonClicked(sync_ui_util::AvatarSyncErrorType error); + void OnCurrentProfileCardClicked(); + void OnSigninButtonClicked(); + void OnSigninAccountButtonClicked(); + void OnSignoutButtonClicked(); + void OnOtherProfileButtonClicked(int profile_index); + // views::StyledLabelListener void StyledLabelLinkClicked(views::StyledLabel* label, const gfx::Range& range,
diff --git a/chrome/browser/ui/views/tabs/tab_unittest.cc b/chrome/browser/ui/views/tabs/tab_unittest.cc index ec758a0..64a2214 100644 --- a/chrome/browser/ui/views/tabs/tab_unittest.cc +++ b/chrome/browser/ui/views/tabs/tab_unittest.cc
@@ -15,7 +15,6 @@ #include "chrome/browser/ui/tabs/tab_group_id.h" #include "chrome/browser/ui/tabs/tab_group_visual_data.h" #include "chrome/browser/ui/tabs/tab_utils.h" -#include "chrome/browser/ui/ui_features.h" #include "chrome/browser/ui/views/tabs/alert_indicator.h" #include "chrome/browser/ui/views/tabs/fake_base_tab_strip_controller.h" #include "chrome/browser/ui/views/tabs/tab_close_button.h" @@ -488,10 +487,6 @@ // Regression test for http://crbug.com/420313: Confirms that any child Views of // Tab do not attempt to provide their own tooltip behavior/text. TEST_F(TabTest, TooltipProvidedByTab) { - // This test isn't relevant when tab hover cards are enabled since tab - // tooltips are then disabled. - if (base::FeatureList::IsEnabled(features::kTabHoverCards)) - return; Widget widget; InitWidget(&widget); @@ -506,9 +501,9 @@ data.favicon = gfx::ImageSkia::CreateFrom1xBitmap(bitmap); data.title = base::UTF8ToUTF16( - "This is a really long tab title that would cause views::Label to " - "provide its own tooltip; but Tab should disable that feature so it can " - "provide the tooltip instead."); + "This is a really long tab title that would case views::Label to provide " + "its own tooltip; but Tab should disable that feature so it can provide " + "the tooltip instead."); // Test both with and without an indicator showing since the tab tooltip text // should include a description of the alert state when the indicator is
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc index 21b43d9..a8fc647 100644 --- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc +++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -232,8 +232,7 @@ continue; } if (shortcut_paths[i] != web_app_path) { - int unique_number = base::GetUniquePathNumber( - shortcut_file, base::FilePath::StringType()); + int unique_number = base::GetUniquePathNumber(shortcut_file); if (unique_number == -1) { success = false; continue;
diff --git a/chrome/browser/web_applications/pending_app_install_task.cc b/chrome/browser/web_applications/pending_app_install_task.cc index 7b714d0c..658503c 100644 --- a/chrome/browser/web_applications/pending_app_install_task.cc +++ b/chrome/browser/web_applications/pending_app_install_task.cc
@@ -221,7 +221,10 @@ std::move(success_closure).Run(); }, std::move(success_closure))); + return; } + + std::move(success_closure).Run(); } } // namespace web_app
diff --git a/chrome/child/pdf_child_init.cc b/chrome/child/pdf_child_init.cc index 209d202..9a744f3c 100644 --- a/chrome/child/pdf_child_init.cc +++ b/chrome/child/pdf_child_init.cc
@@ -7,34 +7,20 @@ #include "build/build_config.h" #if defined(OS_WIN) +#include "base/command_line.h" #include "base/no_destructor.h" #include "base/win/current_module.h" #include "base/win/iat_patch_function.h" #include "base/win/windows_version.h" #include "content/public/child/child_thread.h" +#include "content/public/common/content_switches.h" +#include "services/service_manager/sandbox/switches.h" #endif namespace { #if defined(OS_WIN) -HDC WINAPI CreateDCAPatch(LPCSTR driver_name, - LPCSTR device_name, - LPCSTR output, - const void* init_data) { - DCHECK(std::string("DISPLAY") == std::string(driver_name)); - DCHECK(!device_name); - DCHECK(!output); - DCHECK(!init_data); - - // CreateDC fails behind the sandbox, but not CreateCompatibleDC. - return CreateCompatibleDC(NULL); -} - -typedef DWORD (WINAPI* GetFontDataPtr) (HDC hdc, - DWORD table, - DWORD offset, - LPVOID buffer, - DWORD length); +typedef decltype(::GetFontData)* GetFontDataPtr; GetFontDataPtr g_original_get_font_data = nullptr; @@ -64,39 +50,41 @@ void InitializePDF() { #if defined(OS_WIN) - // Need to patch a few functions for font loading to work correctly. This can - // be removed once we switch PDF to use Skia - // (https://bugs.chromium.org/p/pdfium/issues/detail?id=11). + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + std::string process_type = + command_line.GetSwitchValueASCII(switches::kProcessType); + bool is_pdf_utility_process = false; + if (command_line.HasSwitch(service_manager::switches::kServiceSandboxType)) { + std::string service_sandbox_type = command_line.GetSwitchValueASCII( + service_manager::switches::kServiceSandboxType); + if (service_sandbox_type == + service_manager::switches::kPdfCompositorSandbox) { + is_pdf_utility_process = true; + } + } + // On Win10, pdf does not use GDI fonts and does not need to run this + // initialization for the ppapi process. Printing does still use GDI for + // fonts on Win10 though. + if (is_pdf_utility_process || + (process_type == switches::kPpapiPluginProcess && + base::win::GetVersion() < base::win::Version::WIN10)) { + // Need to patch a few functions for font loading to work correctly. This + // can be removed once we switch PDF to use Skia + // (https://bugs.chromium.org/p/pdfium/issues/detail?id=11). #if defined(COMPONENT_BUILD) - HMODULE module = ::GetModuleHandleA("pdfium.dll"); - DCHECK(module); + HMODULE module = ::GetModuleHandleA("pdfium.dll"); + DCHECK(module); #else - HMODULE module = CURRENT_MODULE(); + HMODULE module = CURRENT_MODULE(); #endif // defined(COMPONENT_BUILD) - // When GDI is delayloaded, calls into real GDI after these patches are - // created result in the delayload handler overwriting the patches when it - // resolves the delayed imports with the full import information. To - // workaround this, we first call into GDI so that the delayed imports get - // resolved, THEN we apply the patches. - // On Win10 this isn't necessary because these methods are not used. - // TODO(crbug.com/988164): Implement a generic IATPatchFunction fix to handle - // these situations. - // TODO(crbug.com/988169): This workaround shouldn't be necessary on Win8 - // either, but is because the win32k process mitigations aren't working - // properly. - if (base::win::GetVersion() < base::win::Version::WIN10) - GetFontData(nullptr, 0, 0, nullptr, 0); - - static base::NoDestructor<base::win::IATPatchFunction> patch_createdca; - patch_createdca->PatchFromModule(module, "gdi32.dll", "CreateDCA", - reinterpret_cast<void*>(CreateDCAPatch)); - - static base::NoDestructor<base::win::IATPatchFunction> patch_get_font_data; - patch_get_font_data->PatchFromModule( - module, "gdi32.dll", "GetFontData", - reinterpret_cast<void*>(GetFontDataPatch)); - g_original_get_font_data = reinterpret_cast<GetFontDataPtr>( - patch_get_font_data->original_function()); + static base::NoDestructor<base::win::IATPatchFunction> patch_get_font_data; + patch_get_font_data->PatchFromModule( + module, "gdi32.dll", "GetFontData", + reinterpret_cast<void*>(GetFontDataPatch)); + g_original_get_font_data = reinterpret_cast<GetFontDataPtr>( + patch_get_font_data->original_function()); + } #endif // defined(OS_WIN) }
diff --git a/chrome/chrome_elf/hook_util/hook_util.cc b/chrome/chrome_elf/hook_util/hook_util.cc index 4687b91b..a820677 100644 --- a/chrome/chrome_elf/hook_util/hook_util.cc +++ b/chrome/chrome_elf/hook_util/hook_util.cc
@@ -105,12 +105,6 @@ if (hook_func_info == nullptr) return false; - // Check for the right module. - if (module == nullptr || - ::strnicmp(module, hook_func_info->imported_from_module, - ::strlen(module)) != 0) - return true; - // Check for the right function. if (import_name == nullptr || ::strnicmp(import_name, hook_func_info->function_name, @@ -178,9 +172,11 @@ // First go through the IAT. If we don't find the import we are looking // for in IAT, search delay import table. - target_image.EnumAllImports(IATFindHookFuncCallback, &hook_info); + target_image.EnumAllImports(IATFindHookFuncCallback, &hook_info, + imported_from_module); if (!hook_info.finished_operation) { - target_image.EnumAllDelayImports(IATFindHookFuncCallback, &hook_info); + target_image.EnumAllDelayImports(IATFindHookFuncCallback, &hook_info, + imported_from_module); } return hook_info.return_code;
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc index b7a09e4..7449154f 100644 --- a/chrome/common/webui_url_constants.cc +++ b/chrome/common/webui_url_constants.cc
@@ -395,7 +395,7 @@ const char kNetworkDetailSubPage[] = "networkDetail"; const char kNetworksSubPage[] = "networks"; const char kPluginVmDetailsSubPage[] = "pluginVm/details"; -const char kPluginVmSharedPathSubPage[] = "pluginVm/sharedPath"; +const char kPluginVmSharedPathsSubPage[] = "pluginVm/sharedPaths"; const char kPointerOverlaySubPage[] = "pointer-overlay"; const char kPowerSubPage[] = "power"; const char kResetSubPage[] = "reset";
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h index 513ef79..bcf8a23 100644 --- a/chrome/common/webui_url_constants.h +++ b/chrome/common/webui_url_constants.h
@@ -351,7 +351,7 @@ extern const char kNetworkDetailSubPage[]; extern const char kNetworksSubPage[]; extern const char kPluginVmDetailsSubPage[]; -extern const char kPluginVmSharedPathSubPage[]; +extern const char kPluginVmSharedPathsSubPage[]; extern const char kPointerOverlaySubPage[]; extern const char kPowerSubPage[]; extern const char kResetSubPage[];
diff --git a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc index 3dc6fc6aa..5f038e61 100644 --- a/chrome/renderer/autofill/password_autofill_agent_browsertest.cc +++ b/chrome/renderer/autofill/password_autofill_agent_browsertest.cc
@@ -746,6 +746,11 @@ ->DidCommitProvisionalLoad(true, ui::PAGE_TRANSITION_LINK); } + void ClearField(FormFieldData* field) { + field->unique_renderer_id = std::numeric_limits<uint32_t>::max(); + field->value.clear(); + } + FakeMojoPasswordManagerDriver fake_driver_; testing::NiceMock<FakePasswordGenerationDriver> fake_pw_client_; @@ -901,9 +906,9 @@ } // Credentials are sent to the renderer even for sign-up forms as these may be -// eligible for filling via manual fall back. In this case, the password_field -// is not set. This test verifies that no failures are recorded in -// PasswordManager.FirstRendererFillingResult. +// eligible for filling via manual fall back. In this case, the username_field +// and password_field are not set. This test verifies that no failures are +// recorded in PasswordManager.FirstRendererFillingResult. TEST_F(PasswordAutofillAgentTest, NoFillingOnSignupForm_NoMetrics) { LoadHTML(kSignupFormHTML); @@ -915,11 +920,8 @@ fill_data_.has_renderer_ids = true; - fill_data_.username_field.name = ASCIIToUTF16("random_info"); fill_data_.username_field.unique_renderer_id = - username_element_.UniqueRendererFormControlId(); - - fill_data_.password_field.name = base::string16(); + FormFieldData::kNotSetFormControlRendererId; fill_data_.password_field.unique_renderer_id = FormFieldData::kNotSetFormControlRendererId; @@ -3899,4 +3901,102 @@ CheckTextFieldsSuggestedState("", false, kAlicePassword, true); } +// Tests that a single username is filled and is exposed to JavaScript only +// after user gesture. +TEST_F(PasswordAutofillAgentTest, FillOnLoadSingleUsername) { + UpdateRendererIDs(); + // Simulate filling single username by clearing password fill data. + ClearField(&fill_data_.password_field); + + SimulateOnFillPasswordForm(fill_data_); + + // The username should have been autofilled. + CheckTextFieldsSuggestedState(kAliceUsername, true, std::string(), false); + + // However, it should have filled with the suggested value, it should not have + // filled with DOM accessible value. + CheckTextFieldsDOMState(std::string(), true, std::string(), false); + + // Simulate a user click so that the username field's real value is filled. + SimulateElementClick(kUsernameName); + CheckTextFieldsDOMState(kAliceUsername, true, std::string(), false); +} + +// Tests that |PreviewSuggestion| properly previews the single username. +TEST_F(PasswordAutofillAgentTest, SingleUsernamePreviewSuggestion) { + UpdateRendererIDs(); + ClearField(&fill_data_.password_field); + // Simulate the browser sending the login info, but set |wait_for_username| to + // prevent the form from being immediately filled. + fill_data_.wait_for_username = true; + SimulateOnFillPasswordForm(fill_data_); + + // Neither field should be autocompleted. + CheckTextFieldsDOMState(std::string(), false, std::string(), false); + + EXPECT_TRUE(password_autofill_agent_->PreviewSuggestion( + username_element_, kAliceUsername, kAlicePassword)); + CheckTextFieldsSuggestedState(kAliceUsername, true, std::string(), false); + + // Try previewing with a username different from the one that was initially + // sent to the renderer. + EXPECT_TRUE(password_autofill_agent_->PreviewSuggestion( + username_element_, kBobUsername, kCarolPassword)); + CheckTextFieldsSuggestedState(kBobUsername, true, std::string(), false); +} + +// Tests that |FillSuggestion| properly fills the single username. +TEST_F(PasswordAutofillAgentTest, SingleUsernameFillSuggestion) { + UpdateRendererIDs(); + ClearField(&fill_data_.password_field); + // Simulate the browser sending the login info, but set |wait_for_username| + // to prevent the form from being immediately filled. + fill_data_.wait_for_username = true; + SimulateOnFillPasswordForm(fill_data_); + + // Neither field should be autocompleted. + CheckTextFieldsDOMState(std::string(), false, std::string(), false); + + // After filling with the suggestion, the username field should be filled. + EXPECT_TRUE(password_autofill_agent_->FillSuggestion( + username_element_, ASCIIToUTF16(kAliceUsername), + ASCIIToUTF16(kAlicePassword))); + CheckTextFieldsDOMState(kAliceUsername, true, std::string(), false); + int username_length = strlen(kAliceUsername); + CheckUsernameSelection(username_length, username_length); + + // Try Filling with a suggestion with a username different from the one that + // was initially sent to the renderer. + EXPECT_TRUE(password_autofill_agent_->FillSuggestion( + username_element_, ASCIIToUTF16(kBobUsername), + ASCIIToUTF16(kCarolPassword))); + CheckTextFieldsDOMState(kBobUsername, true, std::string(), false); + username_length = strlen(kBobUsername); + CheckUsernameSelection(username_length, username_length); +} + +// Tests that |ClearPreview| properly clears previewed single username. +TEST_F(PasswordAutofillAgentTest, SingleUsernameClearPreview) { + UpdateRendererIDs(); + ClearField(&fill_data_.password_field); + ResetFieldState(&username_element_, "ali", WebAutofillState::kPreviewed); + username_element_.SetSelectionRange(3, 3); + + // Simulate the browser sending the login info, but set |wait_for_username| + // to prevent the form from being immediately filled. + fill_data_.wait_for_username = true; + SimulateOnFillPasswordForm(fill_data_); + + CheckTextFieldsDOMState("ali", true, std::string(), false); + + EXPECT_TRUE(password_autofill_agent_->PreviewSuggestion( + username_element_, kAliceUsername, kAlicePassword)); + EXPECT_TRUE( + password_autofill_agent_->DidClearAutofillSelection(username_element_)); + + EXPECT_TRUE(username_element_.SuggestedValue().IsEmpty()); + CheckTextFieldsDOMState("ali", true, std::string(), false); + CheckUsernameSelection(3, 3); +} + } // namespace autofill
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index a5d3e07..b412acf 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -4923,6 +4923,12 @@ "../browser/ui/views/toolbar/toolbar_button_unittest.cc", "../browser/ui/views/translate/translate_bubble_view_unittest.cc", ] + if (enable_native_window_nav_buttons) { + sources += [ "../browser/ui/views/frame/desktop_linux_browser_frame_view_layout_unittest.cc" ] + } + if (enable_plugins) { + sources += [ "../browser/ui/views/hung_plugin_tab_helper_unittest.cc" ] + } if (is_mac) { sources += [ "../browser/ui/views/frame/browser_non_client_frame_view_mac_unittest.mm" ] } @@ -4933,9 +4939,6 @@ "../browser/ui/views/sync/one_click_signin_dialog_view_unittest.cc", ] } - if (enable_native_window_nav_buttons) { - sources += [ "../browser/ui/views/frame/desktop_linux_browser_frame_view_layout_unittest.cc" ] - } if ((is_linux && !is_chromeos) || is_win) { sources += [ "../browser/ui/views/message_center/popups_only_ui_delegate_unittest.cc" ] }
diff --git a/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js b/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js index 0bcf1dd2..cb5e7732 100644 --- a/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js +++ b/chrome/test/data/webui/cr_elements/cr_searchable_drop_down_tests.js
@@ -101,6 +101,19 @@ assertEquals('ta', dropDown.value); }); + test('click closes dropdown', function() { + setItems(['dog', 'cat', 'mouse']); + + dropDown.$.search.click(); + assertTrue(dropDown.$$('iron-dropdown').opened); + + assertNotEquals('dog', dropDown.value); + + getList()[0].click(); + assertEquals('dog', dropDown.value); + assertFalse(dropDown.$$('iron-dropdown').opened); + }); + // If the error-message-allowed flag is passed and the |errorMessage| property // is set, then the error message should be displayed. If the |errorMessage| // property is not set or |errorMessageAllowed| is false, no error message
diff --git a/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js b/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js index 04c7faa4..bcdccedd 100644 --- a/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js +++ b/chrome/test/data/webui/settings/a11y/manage_accessibility_a11y_test.js
@@ -9,10 +9,28 @@ // SettingsAccessibilityTest fixture. GEN_INCLUDE([ + '//chrome/test/data/webui/polymer_browser_test_base.js', 'settings_accessibility_test.js', ]); -AccessibilityTest.define('SettingsAccessibilityTest', { +GEN('#include "chromeos/constants/chromeos_features.h"'); + +// eslint-disable-next-line no-var +var ManageAccessibilityA11yTest = class extends PolymerTest { + /** @override */ + get featureList() { + // Always test with SplitSettings on because the pages are the same in the + // legacy combined settings and we don't want to test everything twice. + return {enabled: ['chromeos::features::kSplitSettings']}; + } + + /** @override */ + get browsePreload() { + return 'chrome://os-settings/'; + } +}; + +AccessibilityTest.define('ManageAccessibilityA11yTest', { /** @override */ name: 'MANAGE_ACCESSIBILITY', /** @override */
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js index e97781a..81cf0223 100644 --- a/chrome/test/data/webui/settings/cr_settings_browsertest.js +++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -618,7 +618,10 @@ browsePreload: 'chrome://settings/people_page/account_manager.html', /** @override */ - featureList: {enabled: ['chromeos::features::kAccountManager']}, + featureList: { + enabled: ['chromeos::features::kAccountManager'], + disabled: ['chromeos::features::kSplitSettings'] + }, /** @override */ extraLibraries: CrSettingsBrowserTestCrOS.prototype.extraLibraries.concat([ @@ -1926,10 +1929,6 @@ mocha.grep(assert(languages_page_tests.TestNames.LanguageMenu)).run(); }); -TEST_F('CrSettingsLanguagesPageTest', 'InputMethods', function() { - mocha.grep(assert(languages_page_tests.TestNames.InputMethods)).run(); -}); - TEST_F('CrSettingsLanguagesPageTest', 'Spellcheck', function() { mocha.grep(assert(languages_page_tests.TestNames.Spellcheck)).run(); }); @@ -1941,6 +1940,35 @@ }); GEN('#endif'); +GEN('#if defined(OS_CHROMEOS)'); +// eslint-disable-next-line no-var +var CrSettingsLanguagesPageTestCrOS = class extends CrSettingsBrowserTestCrOS { + /** @override */ + get browsePreload() { + return 'chrome://settings/languages_page/languages_page.html'; + } + + /** @override */ + get extraLibraries() { + return super.extraLibraries.concat([ + '../fake_chrome_event.js', + '../test_util.js', + '../test_browser_proxy.js', + 'fake_settings_private.js', + 'fake_language_settings_private.js', + 'chromeos/fake_input_method_private.js', + 'test_languages_browser_proxy.js', + 'languages_page_tests.js', + ]); + } +}; + +TEST_F('CrSettingsLanguagesPageTestCrOS', 'InputMethods', function() { + mocha.grep(assert(languages_page_tests.TestNames.InputMethods)).run(); +}); + +GEN('#endif // defined(OS_CHROMEOS)'); + /** * @constructor * @extends {CrSettingsBrowserTest}
diff --git a/chrome/test/data/webui/settings/route_tests.js b/chrome/test/data/webui/settings/route_tests.js index 816f51c..57cf4f58 100644 --- a/chrome/test/data/webui/settings/route_tests.js +++ b/chrome/test/data/webui/settings/route_tests.js
@@ -182,16 +182,6 @@ assertEquals( settings.routes.SITE_SETTINGS_COOKIES, settings.getRouteForPath('/content/cookies/')); - - if (cr.isChromeOS) { - // Path with a dash. - assertEquals( - settings.routes.KEYBOARD, - settings.getRouteForPath('/keyboard-overlay')); - assertEquals( - settings.routes.KEYBOARD, - settings.getRouteForPath('/keyboard-overlay/')); - } }); test('isNavigableDialog', function() {
diff --git a/chrome/test/delayload/delayloads_unittest.cc b/chrome/test/delayload/delayloads_unittest.cc index e03b04d9..fb6c0320 100644 --- a/chrome/test/delayload/delayloads_unittest.cc +++ b/chrome/test/delayload/delayloads_unittest.cc
@@ -51,7 +51,8 @@ ASSERT_TRUE(module_mmap.Initialize(module_path)); base::win::PEImageAsData pe_image_data( reinterpret_cast<HMODULE>(const_cast<uint8_t*>(module_mmap.data()))); - pe_image_data.EnumImportChunks(DelayloadsTest::ImportsCallback, imports); + pe_image_data.EnumImportChunks(DelayloadsTest::ImportsCallback, imports, + nullptr); } }; @@ -324,9 +325,9 @@ ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &dll)); dll = dll.Append(L"chrome_elf.dll"); - // We don't expect user32 to be loaded in chrome_elf_import_unittests. If this + // We don't expect user32 to be loaded in delayloads_unittests. If this // test case fails, then it means that a dependency on user32 has crept into - // the chrome_elf_imports_unittests executable, which needs to be removed. + // the delayloads_unittests executable, which needs to be removed. // NOTE: it may be a secondary dependency of another system DLL. If so, // try adding a "/DELAYLOAD:<blah>.dll" to the build.gn file. ASSERT_EQ(nullptr, ::GetModuleHandle(L"user32.dll"));
diff --git a/chromeos/attestation/attestation_flow.cc b/chromeos/attestation/attestation_flow.cc index 1f78fe5..d1ae0554 100644 --- a/chromeos/attestation/attestation_flow.cc +++ b/chromeos/attestation/attestation_flow.cc
@@ -121,12 +121,14 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const CertificateCallback& callback) { // If this device has not enrolled with the Privacy CA, we need to do that // first. Once enrolled we can proceed with the certificate request. - const base::Closure do_cert_request = base::Bind( - &AttestationFlow::StartCertificateRequest, weak_factory_.GetWeakPtr(), - certificate_profile, account_id, request_origin, force_new_key, callback); + const base::Closure do_cert_request = + base::Bind(&AttestationFlow::StartCertificateRequest, + weak_factory_.GetWeakPtr(), certificate_profile, account_id, + request_origin, force_new_key, key_name, callback); const base::RepeatingClosure on_failure = base::BindRepeating(callback, ATTESTATION_UNSPECIFIED_FAILURE, ""); const base::Closure initiate_enroll = base::Bind( @@ -220,31 +222,35 @@ const AccountId& account_id, const std::string& request_origin, bool generate_new_key, + const std::string& key_name, const CertificateCallback& callback) { AttestationKeyType key_type = GetKeyTypeForProfile(certificate_profile); - std::string key_name = - GetKeyNameForProfile(certificate_profile, request_origin); + std::string attestation_key_name = + !key_name.empty() + ? key_name + : GetKeyNameForProfile(certificate_profile, request_origin); if (generate_new_key) { // Get the attestation service to create a Privacy CA certificate request. async_caller_->AsyncTpmAttestationCreateCertRequest( server_proxy_->GetType(), certificate_profile, cryptohome::Identification(account_id), request_origin, base::Bind(&AttestationFlow::SendCertificateRequestToPCA, - weak_factory_.GetWeakPtr(), key_type, account_id, key_name, - callback)); + weak_factory_.GetWeakPtr(), key_type, account_id, + attestation_key_name, callback)); } else { // If the key already exists, query the existing certificate. const base::Closure on_key_exists = base::Bind( &AttestationFlow::GetExistingCertificate, weak_factory_.GetWeakPtr(), - key_type, account_id, key_name, callback); + key_type, account_id, attestation_key_name, callback); // If the key does not exist, call this method back with |generate_new_key| // set to true. - const base::Closure on_key_not_exists = base::Bind( - &AttestationFlow::StartCertificateRequest, weak_factory_.GetWeakPtr(), - certificate_profile, account_id, request_origin, true, callback); + const base::Closure on_key_not_exists = + base::Bind(&AttestationFlow::StartCertificateRequest, + weak_factory_.GetWeakPtr(), certificate_profile, account_id, + request_origin, true, attestation_key_name, callback); cryptohome_client_->TpmAttestationDoesKeyExist( key_type, cryptohome::CreateAccountIdentifierFromAccountId(account_id), - key_name, + attestation_key_name, base::BindOnce( &DBusBoolRedirectCallback, on_key_exists, on_key_not_exists, base::BindRepeating(callback, ATTESTATION_UNSPECIFIED_FAILURE, ""),
diff --git a/chromeos/attestation/attestation_flow.h b/chromeos/attestation/attestation_flow.h index 6055158..f4e8c50 100644 --- a/chromeos/attestation/attestation_flow.h +++ b/chromeos/attestation/attestation_flow.h
@@ -119,6 +119,8 @@ // force_new_key - If set to true, a new key will be generated even if a key // already exists for the profile. The new key will replace // the existing key on success. + // key_name - The name of the key. If left empty, a default name derived + // from the |certiifcate_profile| and |account_id| will be used. // callback - A callback which will be called when the operation completes. // On success |result| will be true and |data| will contain the // PCA-issued certificate chain in PEM format. @@ -126,6 +128,7 @@ const AccountId& account_id, const std::string& request_origin, bool force_new_key, + const std::string& key_name, const CertificateCallback& callback); private: @@ -199,12 +202,15 @@ // account_id - Identifies the active user. // request_origin - An identifier for the origin of this request. // generate_new_key - If set to true a new key is generated. + // key_name - The name of the key. If left empty, a default name derived + // from the |certiifcate_profile| and |account_id| will be used. // callback - Called when the operation completes. void StartCertificateRequest( const AttestationCertificateProfile certificate_profile, const AccountId& account_id, const std::string& request_origin, bool generate_new_key, + const std::string& key_name, const CertificateCallback& callback); // Called when the attestation daemon has finished creating a certificate
diff --git a/chromeos/attestation/attestation_flow_unittest.cc b/chromeos/attestation/attestation_flow_unittest.cc index 861caa5..5f07c6b 100644 --- a/chromeos/attestation/attestation_flow_unittest.cc +++ b/chromeos/attestation/attestation_flow_unittest.cc
@@ -142,7 +142,8 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, account_id, - "fake_origin", true, mock_callback); + "fake_origin", true, std::string() /* key_name */, + mock_callback); RunUntilIdle(); } @@ -231,7 +232,8 @@ AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.set_retry_delay(base::TimeDelta::FromMilliseconds(30)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, account_id, - "fake_origin", true, callback); + "fake_origin", true, std::string() /* key_name */, + callback); Run(); } @@ -263,7 +265,8 @@ flow.set_ready_timeout(base::TimeDelta::FromMilliseconds(20)); flow.set_retry_delay(base::TimeDelta::FromMilliseconds(6)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), - "fake_origin", true, callback); + "fake_origin", true, std::string() /* key_name */, + callback); Run(); } @@ -292,7 +295,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -325,7 +328,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -364,7 +367,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -407,7 +410,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_MACHINE_CERTIFICATE, EmptyAccountId(), - "", true, mock_callback); + "", true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -450,7 +453,8 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_ENROLLMENT_CERTIFICATE, - EmptyAccountId(), "", true, mock_callback); + EmptyAccountId(), "", true, std::string() /* key_name */, + mock_callback); RunUntilIdle(); } @@ -478,7 +482,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -511,7 +515,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -550,7 +554,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -575,7 +579,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - true, mock_callback); + true, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -618,7 +622,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - false, mock_callback); + false, std::string() /* key_name */, mock_callback); RunUntilIdle(); } @@ -644,7 +648,7 @@ std::unique_ptr<ServerProxy> proxy_interface(proxy.release()); AttestationFlow flow(&async_caller, &client, std::move(proxy_interface)); flow.GetCertificate(PROFILE_ENTERPRISE_USER_CERTIFICATE, EmptyAccountId(), "", - false, mock_callback); + false, std::string() /* key_name */, mock_callback); RunUntilIdle(); }
diff --git a/chromeos/attestation/mock_attestation_flow.h b/chromeos/attestation/mock_attestation_flow.h index 242c8475..49d1606b 100644 --- a/chromeos/attestation/mock_attestation_flow.h +++ b/chromeos/attestation/mock_attestation_flow.h
@@ -69,11 +69,12 @@ MockAttestationFlow(); virtual ~MockAttestationFlow(); - MOCK_METHOD5(GetCertificate, + MOCK_METHOD6(GetCertificate, void(AttestationCertificateProfile, const AccountId& account_id, const std::string&, bool, + const std::string&, /* key_name */ const CertificateCallback&)); };
diff --git a/chromeos/cryptohome/async_method_caller.cc b/chromeos/cryptohome/async_method_caller.cc index 4173810..7450b5f 100644 --- a/chromeos/cryptohome/async_method_caller.cc +++ b/chromeos/cryptohome/async_method_caller.cc
@@ -104,10 +104,11 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const DataCallback& callback) override { CryptohomeClient::Get()->TpmAttestationSignEnterpriseChallenge( key_type, CreateAccountIdentifierFromIdentification(cryptohome_id), - key_name, domain, device_id, options, challenge, + key_name, domain, device_id, options, challenge, key_name_for_spkac, base::BindOnce( &AsyncMethodCallerImpl::RegisterAsyncDataCallback, weak_ptr_factory_.GetWeakPtr(), callback,
diff --git a/chromeos/cryptohome/async_method_caller.h b/chromeos/cryptohome/async_method_caller.h index ae8410b..65b8800 100644 --- a/chromeos/cryptohome/async_method_caller.h +++ b/chromeos/cryptohome/async_method_caller.h
@@ -94,6 +94,9 @@ // the challenge response. If |key_type| is KEY_USER, a |user_id| must be // provided. Otherwise |user_id| is ignored. For normal GAIA users the // |user_id| is an AccountaId-derived string (see AccountId::GetAccountIdKey). + // If |key_name_for_spkac| is not empty, then the corresponding key will be + // used for SignedPublicKeyAndChallenge, but the challenge response will still + // be signed by the key specified by |key_name| (EMK or EUK). virtual void TpmAttestationSignEnterpriseChallenge( chromeos::attestation::AttestationKeyType key_type, const Identification& user_id, @@ -102,6 +105,7 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const DataCallback& callback) = 0; // Asks cryptohomed to asynchronously sign a simple challenge with the key
diff --git a/chromeos/cryptohome/mock_async_method_caller.cc b/chromeos/cryptohome/mock_async_method_caller.cc index 5d12363..a6041e4 100644 --- a/chromeos/cryptohome/mock_async_method_caller.cc +++ b/chromeos/cryptohome/mock_async_method_caller.cc
@@ -41,10 +41,10 @@ .WillByDefault( WithArgs<4>(Invoke(this, &MockAsyncMethodCaller::FakeFinishCertRequest))); - ON_CALL(*this, TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _)) - .WillByDefault( - WithArgs<7>(Invoke(this, - &MockAsyncMethodCaller::FakeEnterpriseChallenge))); + ON_CALL(*this, + TpmAttestationSignEnterpriseChallenge(_, _, _, _, _, _, _, _, _)) + .WillByDefault(WithArgs<8>( + Invoke(this, &MockAsyncMethodCaller::FakeEnterpriseChallenge))); ON_CALL(*this, TpmAttestationRegisterKey(_, _, _, _)) .WillByDefault( WithArgs<3>(Invoke(this, &MockAsyncMethodCaller::DoCallback)));
diff --git a/chromeos/cryptohome/mock_async_method_caller.h b/chromeos/cryptohome/mock_async_method_caller.h index a0003fb..10fad7aa 100644 --- a/chromeos/cryptohome/mock_async_method_caller.h +++ b/chromeos/cryptohome/mock_async_method_caller.h
@@ -53,7 +53,7 @@ const Identification& user_id, const std::string& key_name, const Callback& callback)); - MOCK_METHOD8(TpmAttestationSignEnterpriseChallenge, + MOCK_METHOD9(TpmAttestationSignEnterpriseChallenge, void(chromeos::attestation::AttestationKeyType key_type, const Identification& user_id, const std::string& key_name, @@ -61,6 +61,7 @@ const std::string& device_id, chromeos::attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, const DataCallback& callback)); MOCK_METHOD5(TpmAttestationSignSimpleChallenge, void(chromeos::attestation::AttestationKeyType key_type,
diff --git a/chromeos/dbus/cryptohome/cryptohome_client.cc b/chromeos/dbus/cryptohome/cryptohome_client.cc index e4f9032..11e6d92 100644 --- a/chromeos/dbus/cryptohome/cryptohome_client.cc +++ b/chromeos/dbus/cryptohome/cryptohome_client.cc
@@ -673,10 +673,11 @@ const std::string& device_id, attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, AsyncMethodCallback callback) override { dbus::MethodCall method_call( cryptohome::kCryptohomeInterface, - cryptohome::kCryptohomeTpmAttestationSignEnterpriseVaChallenge); + cryptohome::kCryptohomeTpmAttestationSignEnterpriseVaChallengeV2); dbus::MessageWriter writer(&method_call); writer.AppendInt32(GetVerifiedAccessType()); bool is_user_specific = (key_type == attestation::KEY_USER); @@ -691,6 +692,7 @@ writer.AppendBool(include_signed_public_key); writer.AppendArrayOfBytes( reinterpret_cast<const uint8_t*>(challenge.data()), challenge.size()); + writer.AppendString(key_name_for_spkac); proxy_->CallMethod( &method_call, kTpmDBusTimeoutMs, base::BindOnce(&CryptohomeClientImpl::OnAsyncMethodCall,
diff --git a/chromeos/dbus/cryptohome/cryptohome_client.h b/chromeos/dbus/cryptohome/cryptohome_client.h index 5e06f76..b79253b1 100644 --- a/chromeos/dbus/cryptohome/cryptohome_client.h +++ b/chromeos/dbus/cryptohome/cryptohome_client.h
@@ -423,7 +423,10 @@ // The |callback| will be called when the dbus call completes. When the // operation completes, the AsyncCallStatusWithDataHandler signal handler is // called. If |key_type| is KEY_USER, a |id| must be provided. - // Otherwise |id| is ignored. + // Otherwise |id| is ignored. If |key_name_for_spkac| is not empty, then the + // corresponding key will be used for SignedPublicKeyAndChallenge, but the + // challenge response will still be signed by the key specified by |key_name| + // (EMK or EUK). virtual void TpmAttestationSignEnterpriseChallenge( attestation::AttestationKeyType key_type, const cryptohome::AccountIdentifier& id, @@ -432,6 +435,7 @@ const std::string& device_id, attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, AsyncMethodCallback callback) = 0; // Asynchronously signs a simple challenge with the key specified by
diff --git a/chromeos/dbus/cryptohome/fake_cryptohome_client.cc b/chromeos/dbus/cryptohome/fake_cryptohome_client.cc index 500a38d..769a7772 100644 --- a/chromeos/dbus/cryptohome/fake_cryptohome_client.cc +++ b/chromeos/dbus/cryptohome/fake_cryptohome_client.cc
@@ -472,6 +472,7 @@ const std::string& device_id, attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, AsyncMethodCallback callback) { ReturnAsyncMethodData(std::move(callback), std::string()); }
diff --git a/chromeos/dbus/cryptohome/fake_cryptohome_client.h b/chromeos/dbus/cryptohome/fake_cryptohome_client.h index 25feced..9abe2695 100644 --- a/chromeos/dbus/cryptohome/fake_cryptohome_client.h +++ b/chromeos/dbus/cryptohome/fake_cryptohome_client.h
@@ -150,6 +150,7 @@ const std::string& device_id, attestation::AttestationChallengeOptions options, const std::string& challenge, + const std::string& key_name_for_spkac, AsyncMethodCallback callback) override; void TpmAttestationSignSimpleChallenge( attestation::AttestationKeyType key_type,
diff --git a/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc b/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc index 2b6550e..9af4b404 100644 --- a/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc +++ b/chromeos/services/secure_channel/ble_scanner_impl_unittest.cc
@@ -112,6 +112,14 @@ /*is_error=*/false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS); })); + ON_CALL(*mock_adapter_, StopScan(testing::_)) + .WillByDefault(testing::Invoke( + [](device::BluetoothAdapter::DiscoverySessionResultCallback + callback) { + std::move(callback).Run( + /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + })); } void AddScanFilter(const BleScanner::ScanFilter& scan_filter) {
diff --git a/chromeos/services/secure_channel/ble_synchronizer_unittest.cc b/chromeos/services/secure_channel/ble_synchronizer_unittest.cc index a8578a1..a136424 100644 --- a/chromeos/services/secure_channel/ble_synchronizer_unittest.cc +++ b/chromeos/services/secure_channel/ble_synchronizer_unittest.cc
@@ -180,10 +180,9 @@ ON_CALL(*mock_adapter_, StartScanWithFilter_(_, _)) .WillByDefault(Invoke( this, &SecureChannelBleSynchronizerTest::OnAdapterStartScan)); - ON_CALL(*mock_adapter_, RemoveDiscoverySession_(_, _, _)) - .WillByDefault(Invoke( - this, - &SecureChannelBleSynchronizerTest::OnDiscoverySessionRemoved)); + ON_CALL(*mock_adapter_, StopScan(_)) + .WillByDefault( + Invoke(this, &SecureChannelBleSynchronizerTest::OnStopScan)); mock_timer_ = new base::MockOneShotTimer(); @@ -377,18 +376,14 @@ } void InvokeStopDiscoveryCallback( - bool success, size_t stop_arg_index, size_t expected_stop_discovery_result_count) { EXPECT_TRUE(stop_discovery_args_list_.size() >= stop_arg_index); - if (success) - stop_discovery_args_list_[stop_arg_index]->callback.Run(); - else - stop_discovery_args_list_[stop_arg_index]->error_callback.Run(); + stop_discovery_args_list_[stop_arg_index]->callback.Run(); histogram_tester_.ExpectUniqueSample( - "InstantTethering.BluetoothDiscoverySessionStopped", success ? 1 : 0, + "InstantTethering.BluetoothDiscoverySessionStopped", 1, expected_stop_discovery_result_count); // Reset to make sure that this callback is never double-invoked. @@ -396,7 +391,10 @@ test_task_runner_->RunUntilIdle(); } - void OnDiscoverySessionStopped() { ++num_stop_success_; } + void OnDiscoverySessionStopped() { + discovery_session_.reset(); + ++num_stop_success_; + } void OnErrorStoppingDiscoverySession() { ++num_stop_error_; } @@ -412,17 +410,18 @@ new UnregisterAdvertisementArgs(callback, error_callback))); } - void OnDiscoverySessionRemoved( - device::BluetoothDiscoveryFilter* discovery_filter, - const base::RepeatingClosure& callback, - device::BluetoothAdapter::DiscoverySessionErrorCallback& error_callback) { - auto repeating_error_callback = - base::AdaptCallbackForRepeating(std::move(error_callback)); + void OnStopScan( + device::BluetoothAdapter::DiscoverySessionResultCallback callback) { + auto repeating_callback = + base::AdaptCallbackForRepeating(std::move(callback)); stop_discovery_args_list_.emplace_back( base::WrapUnique(new StopDiscoverySessionArgs( - callback, base::BindRepeating( - repeating_error_callback, + repeating_callback, /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS), + base::BindRepeating( + repeating_callback, + /*is_error=*/true, device::UMABluetoothDiscoverySessionOutcome::UNKNOWN)))); } @@ -532,29 +531,11 @@ test_clock_.Advance(TimeDeltaMillis(kTimeBetweenEachCommandMs)); mock_timer_->Fire(); - InvokeStopDiscoveryCallback(true /* success */, 0u /* unreg_arg_index */, + InvokeStopDiscoveryCallback(0u /* unreg_arg_index */, 1 /* expected_stop_discovery_result_count */); EXPECT_EQ(1, num_stop_success_); } -TEST_F(SecureChannelBleSynchronizerTest, TestStopError) { - StartDiscoverySession(); - InvokeStartDiscoveryCallback(true /* success */, 0u /* reg_arg_index */, - 1 /* expected_start_discovery_result_count */); - EXPECT_EQ(1, num_start_success_); - - StopDiscoverySession(discovery_session_weak_ptr_factory_->GetWeakPtr()); - - // Advance the clock and fire the timer. This should result in the next - // command being executed. - test_clock_.Advance(TimeDeltaMillis(kTimeBetweenEachCommandMs)); - mock_timer_->Fire(); - - InvokeStopDiscoveryCallback(false /* success */, 0u /* unreg_arg_index */, - 1 /* expected_stop_discovery_result_count */); - EXPECT_EQ(1, num_stop_error_); -} - TEST_F(SecureChannelBleSynchronizerTest, TestStop_DeletedDiscoverySession) { // Simulate an invalidated WeakPtr being processed. StopDiscoverySession(base::WeakPtr<device::BluetoothDiscoverySession>());
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc index ebe0b002..2ee9d3c 100644 --- a/components/arc/ime/arc_ime_service.cc +++ b/components/arc/ime/arc_ime_service.cc
@@ -253,6 +253,13 @@ } } +void ArcImeService::OnWindowRemoved(aura::Window* removed_window) { + // |this| can lose the IME focus because |focused_arc_window_| may have + // children other than ExoSurface e.g. WebContentsViewAura for CustomTabs. + // Restore the IME focus when such a window is removed. + ReattachInputMethod(nullptr, focused_arc_window_); +} + //////////////////////////////////////////////////////////////////////////////// // Overridden from exo::WMHelper::FocusChangeObserver:
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h index 2b3276e..8b59b60 100644 --- a/components/arc/ime/arc_ime_service.h +++ b/components/arc/ime/arc_ime_service.h
@@ -84,6 +84,7 @@ void OnWindowPropertyChanged(aura::Window* window, const void* key, intptr_t old) override; + void OnWindowRemoved(aura::Window* removed_window) override; // Overridden from aura::client::FocusChangeObserver: void OnWindowFocused(aura::Window* gained_focus,
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc index 057cf0f..4a05bda 100644 --- a/components/autofill/content/renderer/password_autofill_agent.cc +++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -772,7 +772,8 @@ if (!FindPasswordInfoForElement(*element, &username_element, &password_element, &password_info) || - !IsElementAutocompletable(password_element)) { + (!password_element.IsNull() && + !IsElementAutocompletable(password_element))) { return false; } @@ -784,7 +785,7 @@ // Call OnFieldAutofilled before WebInputElement::SetAutofillState which may // cause frame closing. - if (password_generation_agent_) + if (!password_element.IsNull() && password_generation_agent_) password_generation_agent_->OnFieldAutofilled(password_element); if (IsUsernameAmendable(username_element, @@ -793,7 +794,8 @@ FillField(&username_element, username); } - FillPasswordFieldAndSave(&password_element, password); + if (!password_element.IsNull()) + FillPasswordFieldAndSave(&password_element, password); WebInputElement mutable_filled_element = *element; mutable_filled_element.SetSelectionRange(element->Value().length(), @@ -850,7 +852,8 @@ if (!FindPasswordInfoForElement(*element, &username_element, &password_element, &password_info) || - !IsElementAutocompletable(password_element)) { + (!password_element.IsNull() && + !IsElementAutocompletable(password_element))) { return false; } @@ -865,9 +868,11 @@ form_util::PreviewSuggestion(username_element.SuggestedValue().Utf16(), username_query_prefix_, &username_element); } - password_autofill_state_ = password_element.GetAutofillState(); - password_element.SetSuggestedValue(password); - password_element.SetAutofillState(WebAutofillState::kPreviewed); + if (!password_element.IsNull()) { + password_autofill_state_ = password_element.GetAutofillState(); + password_element.SetSuggestedValue(password); + password_element.SetAutofillState(WebAutofillState::kPreviewed); + } return true; } @@ -1019,8 +1024,10 @@ // password form and that the request to show suggestions has been handled (as // a no-op). if (!element.IsTextField() || !IsElementAutocompletable(element) || - !IsElementAutocompletable(password_element)) + (!password_element.IsNull() && + !IsElementAutocompletable(password_element))) { return true; + } if (element.NameForAutofill().IsEmpty() && !DoesFormContainAmbiguousOrEmptyNames(password_info->fill_data)) { @@ -1406,18 +1413,29 @@ GetPasswordManagerDriver().get())); logger->LogMessage(Logger::STRING_ON_FILL_PASSWORD_FORM_METHOD); } + + bool username_password_fields_not_set = + form_data.username_field.unique_renderer_id == + FormFieldData::kNotSetFormControlRendererId && + form_data.password_field.unique_renderer_id == + FormFieldData::kNotSetFormControlRendererId; + if (username_password_fields_not_set) { + // No fields for filling were found during parsing, which means filling + // fallback case. So save data for fallback filling. + MaybeStoreFallbackData(form_data); + return; + } + WebInputElement username_element, password_element; std::tie(username_element, password_element) = FindUsernamePasswordElements(form_data); - if (password_element.IsNull()) { + bool is_single_username_fill = form_data.password_field.unique_renderer_id == + FormFieldData::kNotSetFormControlRendererId; + WebElement main_element = + is_single_username_fill ? username_element : password_element; + if (main_element.IsNull()) { MaybeStoreFallbackData(form_data); - if (form_data.password_field.unique_renderer_id == - FormFieldData::kNotSetFormControlRendererId) { - // If the password_field.unique_renderer_id was not set, this was never - // meant as an honest attempt to fill the form. Therefore, don't log it as - // such. - return; - } + // TODO(https://crbug.com/959776): Fix logging for single username. LogFirstFillingResult(form_data, FillingResult::kNoPasswordElement); return; } @@ -1695,7 +1713,7 @@ username->SetSelectionRange(username_query_prefix_.length(), username->Value().length()); } - if (!password->SuggestedValue().IsEmpty()) { + if (!password->IsNull() && !password->SuggestedValue().IsEmpty()) { password->SetSuggestedValue(WebString()); password->SetAutofillState(password_autofill_state_); } @@ -1741,7 +1759,11 @@ if (logger) logger->LogMessage(Logger::STRING_FILL_USERNAME_AND_PASSWORD_METHOD); - if (IsInCrossOriginIframe(password_element)) { + bool is_single_username_fill = password_element.IsNull(); + WebInputElement main_element = + is_single_username_fill ? username_element : password_element; + + if (IsInCrossOriginIframe(main_element)) { if (logger) logger->LogMessage(Logger::STRING_FAILED_TO_FILL_INTO_IFRAME); LogFirstFillingResult(fill_data, FillingResult::kBlockedByFrameHierarchy); @@ -1749,7 +1771,7 @@ } // Don't fill username if password can't be set. - if (!IsElementAutocompletable(password_element)) { + if (!IsElementAutocompletable(main_element)) { if (logger) { logger->LogMessage( Logger::STRING_FAILED_TO_FILL_NO_AUTOCOMPLETEABLE_ELEMENT); @@ -1807,7 +1829,7 @@ FindMatchesByUsername(fill_data, current_username, exact_username_match, logger, &username, &password); - if (password.empty()) { + if (password.empty() && !is_single_username_fill) { if (!username_element.IsNull() && !username_element.Value().IsEmpty() && !prefilled_placeholder_username) { LogPrefilledUsernameFillOutcome( @@ -1829,7 +1851,7 @@ // Call OnFieldAutofilled before WebInputElement::SetAutofillState which may // cause frame closing. - if (password_generation_agent_) + if (password_generation_agent_ && !is_single_username_fill) password_generation_agent_->OnFieldAutofilled(password_element); // Input matches the username, fill in required values. @@ -1849,10 +1871,11 @@ logger->LogElementName(Logger::STRING_USERNAME_FILLED, username_element); } - AutofillField(password, password_element); - - if (logger) - logger->LogElementName(Logger::STRING_PASSWORD_FILLED, password_element); + if (!is_single_username_fill) { + AutofillField(password, password_element); + if (logger) + logger->LogElementName(Logger::STRING_PASSWORD_FILLED, password_element); + } LogFirstFillingResult(fill_data, FillingResult::kSuccess); return true;
diff --git a/components/autofill/core/common/password_form.cc b/components/autofill/core/common/password_form.cc index 17bfc76e..dd47905 100644 --- a/components/autofill/core/common/password_form.cc +++ b/components/autofill/core/common/password_form.cc
@@ -108,16 +108,33 @@ return IsPossibleChangePasswordForm() && username_element.empty(); } +bool PasswordForm::HasUsernameElement() const { + return has_renderer_ids ? username_element_renderer_id != + FormFieldData::kNotSetFormControlRendererId + : !username_element.empty(); +} + bool PasswordForm::HasPasswordElement() const { return has_renderer_ids ? password_element_renderer_id != FormFieldData::kNotSetFormControlRendererId : !password_element.empty(); } +bool PasswordForm::HasNewPasswordElement() const { + return has_renderer_ids ? new_password_element_renderer_id != + FormFieldData::kNotSetFormControlRendererId + : !new_password_element.empty(); +} + bool PasswordForm::IsFederatedCredential() const { return !federation_origin.opaque(); } +bool PasswordForm::IsSingleUsername() const { + return HasUsernameElement() && !HasPasswordElement() && + !HasNewPasswordElement(); +} + bool PasswordForm::operator==(const PasswordForm& form) const { return scheme == form.scheme && signon_realm == form.signon_realm && origin == form.origin && action == form.action &&
diff --git a/components/autofill/core/common/password_form.h b/components/autofill/core/common/password_form.h index 4d8c4eb..64a062e 100644 --- a/components/autofill/core/common/password_form.h +++ b/components/autofill/core/common/password_form.h
@@ -305,11 +305,21 @@ bool IsPossibleChangePasswordFormWithoutUsername() const; // Returns true if current password element is set. + bool HasUsernameElement() const; + + // Returns true if current password element is set. bool HasPasswordElement() const; + // Returns true if current password element is set. + bool HasNewPasswordElement() const; + // True iff |federation_origin| isn't empty. bool IsFederatedCredential() const; + // True if username element is set and password and new password elements are + // not set. + bool IsSingleUsername() const; + // Equality operators for testing. bool operator==(const PasswordForm& form) const; bool operator!=(const PasswordForm& form) const;
diff --git a/components/autofill/core/common/password_form_fill_data.cc b/components/autofill/core/common/password_form_fill_data.cc index 920903ca..db08ce0 100644 --- a/components/autofill/core/common/password_form_fill_data.cc +++ b/components/autofill/core/common/password_form_fill_data.cc
@@ -38,10 +38,11 @@ // by the password autocomplete code. username_field.value = preferred_match.username_value; password_field.value = preferred_match.password_value; - if (!form_on_page.only_for_fallback) { - // Fill fields identifying information only for non-fallback case. In - // fallback case, a fill popup is shown on clicking on each password - // field so no need in any field identifiers. + if (!form_on_page.only_for_fallback && + (form_on_page.HasPasswordElement() || form_on_page.IsSingleUsername())) { + // Fill fields identifying information only for non-fallback case when + // password element is found. In other cases a fill popup is shown on + // clicking on each password field so no need in any field identifiers. username_field.name = form_on_page.username_element; username_field.unique_renderer_id = form_on_page.username_element_renderer_id;
diff --git a/components/autofill/core/common/password_form_fill_data_unittest.cc b/components/autofill/core/common/password_form_fill_data_unittest.cc index c6f5002..b794cc1 100644 --- a/components/autofill/core/common/password_form_fill_data_unittest.cc +++ b/components/autofill/core/common/password_form_fill_data_unittest.cc
@@ -262,4 +262,39 @@ EXPECT_TRUE(result.username_may_use_prefilled_placeholder); } +// Tests that nor username nor password fields are set when password element is +// not found. +TEST(PasswordFormFillDataTest, NoPasswordElement) { + // Create the current form on the page. + PasswordForm form_on_page; + form_on_page.origin = GURL("https://foo.com/"); + form_on_page.has_renderer_ids = true; + form_on_page.username_element_renderer_id = 123; + // Set no password element. + form_on_page.password_element_renderer_id = + std::numeric_limits<uint32_t>::max(); + form_on_page.new_password_element_renderer_id = 456; + + // Create an exact match in the database. + PasswordForm preferred_match = form_on_page; + preferred_match.username_value = ASCIIToUTF16("test@gmail.com"); + preferred_match.password_value = ASCIIToUTF16("test"); + preferred_match.preferred = true; + + FormData form_data; + form_data.unique_renderer_id = 42; + form_data.is_form_tag = true; + form_on_page.form_data = form_data; + + PasswordFormFillData result(form_on_page, {} /* matches */, preferred_match, + true); + + // Check that nor username nor password fields are set. + EXPECT_EQ(true, result.has_renderer_ids); + EXPECT_EQ(std::numeric_limits<uint32_t>::max(), + result.username_field.unique_renderer_id); + EXPECT_EQ(std::numeric_limits<uint32_t>::max(), + result.password_field.unique_renderer_id); +} + } // namespace autofill
diff --git a/components/background_task_scheduler/BUILD.gn b/components/background_task_scheduler/BUILD.gn index 7db9b4d..7349c59 100644 --- a/components/background_task_scheduler/BUILD.gn +++ b/components/background_task_scheduler/BUILD.gn
@@ -30,9 +30,9 @@ android_library("background_task_scheduler_java") { java_files = [ "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTask.java", + "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskFactory.java", "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskService.java", "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobService.java", - "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskReflection.java", "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskScheduler.java", "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerDelegate.java", "android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerExternalUma.java", @@ -96,6 +96,7 @@ "android/junit/src/org/chromium/components/background_task_scheduler/ShadowGcmNetworkManager.java", "android/junit/src/org/chromium/components/background_task_scheduler/TaskInfoTest.java", "android/junit/src/org/chromium/components/background_task_scheduler/TestBackgroundTask.java", + "android/junit/src/org/chromium/components/background_task_scheduler/TestBackgroundTaskFactory.java", ] deps = [
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskFactory.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskFactory.java new file mode 100644 index 0000000..92c5a3e --- /dev/null +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskFactory.java
@@ -0,0 +1,18 @@ +// 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.components.background_task_scheduler; + +/** + * Generic factory interface to inject into {@link BackgroundTaskSchedulerFactory}. + * Exposes the interface call for getting the BackgroundTask class instance from the task id. + */ +public interface BackgroundTaskFactory { + /** + * Creates a BackgroundTask class instance for a given task id. + * @param taskId the task id for which to create a BackgroundTask class instance. + * @return an instance of the corresponding BackgroundTask class or null if task id is unknown. + */ + BackgroundTask getBackgroundTaskFromTaskId(int taskId); +}
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskService.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskService.java index f65ba64..0212e2c3a 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskService.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskService.java
@@ -91,16 +91,20 @@ @Override public int onRunTask(TaskParams params) { - final BackgroundTask backgroundTask = - BackgroundTaskSchedulerGcmNetworkManager.getBackgroundTaskFromTaskParams(params); - if (backgroundTask == null) { - Log.w(TAG, "Failed to start task. Could not instantiate class."); - return GcmNetworkManager.RESULT_FAILURE; - } - final TaskParameters taskParams = BackgroundTaskSchedulerGcmNetworkManager.getTaskParametersFromTaskParams(params); + final BackgroundTask backgroundTask = + BackgroundTaskSchedulerFactory.getBackgroundTaskFromTaskId(taskParams.getTaskId()); + if (backgroundTask == null) { + Log.w(TAG, "Failed to start task. Could not instantiate BackgroundTask class."); + // Cancel task if the BackgroundTask class is not found anymore. We assume this means + // that the task has been deprecated. + BackgroundTaskSchedulerFactory.getScheduler().cancel( + ContextUtils.getApplicationContext(), taskParams.getTaskId()); + return GcmNetworkManager.RESULT_FAILURE; + } + Long deadlineTime = BackgroundTaskSchedulerGcmNetworkManager.getDeadlineTimeFromTaskParams(params); if (deadlineTime != null && mClock.currentTimeMillis() >= deadlineTime) {
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobService.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobService.java index 1cf0dce..8263d59 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobService.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobService.java
@@ -75,9 +75,13 @@ public boolean onStartJob(JobParameters params) { ThreadUtils.assertOnUiThread(); BackgroundTask backgroundTask = - BackgroundTaskSchedulerJobService.getBackgroundTaskFromJobParameters(params); + BackgroundTaskSchedulerFactory.getBackgroundTaskFromTaskId(params.getJobId()); if (backgroundTask == null) { - Log.w(TAG, "Failed to start task. Could not instantiate class."); + Log.w(TAG, "Failed to start task. Could not instantiate BackgroundTask class."); + // Cancel task if the BackgroundTask class is not found anymore. We assume this means + // that the task has been deprecated. + BackgroundTaskSchedulerFactory.getScheduler().cancel( + ContextUtils.getApplicationContext(), params.getJobId()); return false; }
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskReflection.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskReflection.java deleted file mode 100644 index 91bbbefc5..0000000 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskReflection.java +++ /dev/null
@@ -1,73 +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. - -package org.chromium.components.background_task_scheduler; - -import android.support.annotation.Nullable; - -import org.chromium.base.Log; - -import java.lang.reflect.Constructor; - -/** - * BakgroundTaskReflection contains functionality to construct {@link BackgroundTask} instances from - * their classname and to inspect whether a particular {@link BackgroundTask} has a parameterless - * constructor, which is required for any {@link BackgroundTask}. - */ -final class BackgroundTaskReflection { - private static final String TAG = "BkgrdTaskReflect"; - - /** - * Uses reflection to find the given class and instantiates a {@link BackgroundTask} if the - * class is valid. - * - * @param backgroundTaskClassName the full class name to look for. - * @return a new {@link BackgroundTask} instance if successful or null when a failure occurs. - */ - @Nullable - static BackgroundTask getBackgroundTaskFromClassName(String backgroundTaskClassName) { - if (backgroundTaskClassName == null) return null; - - Class<?> clazz; - try { - clazz = Class.forName(backgroundTaskClassName); - } catch (ClassNotFoundException e) { - Log.w(TAG, "Unable to find BackgroundTask class with name " + backgroundTaskClassName); - return null; - } - - if (!BackgroundTask.class.isAssignableFrom(clazz)) { - Log.w(TAG, "Class " + clazz + " is not a BackgroundTask"); - return null; - } - - try { - return (BackgroundTask) clazz.newInstance(); - } catch (InstantiationException e) { - Log.w(TAG, "Unable to instantiate class (InstExc) " + clazz); - return null; - } catch (IllegalAccessException e) { - Log.w(TAG, "Unable to instantiate class (IllAccExc) " + clazz); - return null; - } - } - - /** - * Inspects all public constructors of the given class, and returns true if one of them is - * parameterless. - * - * @param clazz the class to inspect. - * @return whether the class has a parameterless constructor. - */ - static boolean hasParameterlessPublicConstructor(Class<? extends BackgroundTask> clazz) { - for (Constructor<?> constructor : clazz.getConstructors()) { - if (constructor.getParameterTypes().length == 0) return true; - } - return false; - } - - private BackgroundTaskReflection() { - // No instantiation. - } -}
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java index 69133883..8dd0905 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerFactory.java
@@ -13,7 +13,8 @@ * A factory for {@link BackgroundTaskScheduler} that ensures there is only ever a single instance. */ public final class BackgroundTaskSchedulerFactory { - private static BackgroundTaskScheduler sInstance; + private static BackgroundTaskScheduler sBackgroundTaskScheduler; + private static BackgroundTaskFactory sBackgroundTaskFactory; static BackgroundTaskSchedulerDelegate getSchedulerDelegateForSdk(int sdkInt) { if (sdkInt >= Build.VERSION_CODES.M) { @@ -29,16 +30,34 @@ */ public static BackgroundTaskScheduler getScheduler() { ThreadUtils.assertOnUiThread(); - if (sInstance == null) { - sInstance = new BackgroundTaskSchedulerImpl( + if (sBackgroundTaskScheduler == null) { + sBackgroundTaskScheduler = new BackgroundTaskSchedulerImpl( getSchedulerDelegateForSdk(Build.VERSION.SDK_INT)); } - return sInstance; + return sBackgroundTaskScheduler; } @VisibleForTesting - public static void setSchedulerForTesting(BackgroundTaskScheduler scheduler) { - sInstance = scheduler; + public static void setSchedulerForTesting(BackgroundTaskScheduler backgroundTaskScheduler) { + sBackgroundTaskScheduler = backgroundTaskScheduler; + } + + /** + * @param taskId id of the scheduled task. + * @return instance of the {@link BackgroundTask} that implements the functionality for the + * task id. + */ + public static BackgroundTask getBackgroundTaskFromTaskId(int taskId) { + assert sBackgroundTaskFactory != null; + return sBackgroundTaskFactory.getBackgroundTaskFromTaskId(taskId); + } + + /** + * @param backgroundTaskFactory specific implementation of {@link BackgroundTaskFactory} of + * the caller. + */ + public static void setBackgroundTaskFactory(BackgroundTaskFactory backgroundTaskFactory) { + sBackgroundTaskFactory = backgroundTaskFactory; } // Do not instantiate.
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java index 5715890..36fb2e9 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManager.java
@@ -42,17 +42,6 @@ sClock = clock; } - static BackgroundTask getBackgroundTaskFromTaskParams(@NonNull TaskParams taskParams) { - String backgroundTaskClassName = getBackgroundTaskClassFromTaskParams(taskParams); - return BackgroundTaskReflection.getBackgroundTaskFromClassName(backgroundTaskClassName); - } - - private static String getBackgroundTaskClassFromTaskParams(@NonNull TaskParams taskParams) { - Bundle extras = taskParams.getExtras(); - if (extras == null) return null; - return extras.getString(BACKGROUND_TASK_CLASS_KEY); - } - static Long getDeadlineTimeFromTaskParams(@NonNull TaskParams taskParams) { Bundle extras = taskParams.getExtras(); if (extras == null || !extras.containsKey(BACKGROUND_TASK_DEADLINE_KEY)) { @@ -95,8 +84,6 @@ @VisibleForTesting static Task createTaskFromTaskInfo(@NonNull TaskInfo taskInfo) { Bundle taskExtras = new Bundle(); - taskExtras.putString( - BACKGROUND_TASK_CLASS_KEY, taskInfo.getBackgroundTaskClass().getName()); if (!taskInfo.isPeriodic() && taskInfo.getOneOffInfo().expiresAfterWindowEndTime()) { taskExtras.putLong(BACKGROUND_TASK_DEADLINE_KEY, getDeadlineTime(taskInfo)); } @@ -163,13 +150,6 @@ @Override public boolean schedule(Context context, @NonNull TaskInfo taskInfo) { ThreadUtils.assertOnUiThread(); - if (!BackgroundTaskReflection.hasParameterlessPublicConstructor( - taskInfo.getBackgroundTaskClass())) { - Log.e(TAG, - "BackgroundTask " + taskInfo.getBackgroundTaskClass() - + " has no parameterless public constructor."); - return false; - } GcmNetworkManager gcmNetworkManager = getGcmNetworkManager(context); if (gcmNetworkManager == null) {
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java index f1a64d5..d91b0677 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImpl.java
@@ -8,6 +8,7 @@ import android.os.Build; import org.chromium.base.CommandLine; +import org.chromium.base.ContextUtils; import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; @@ -104,17 +105,23 @@ public void reschedule(Context context) { try (TraceEvent te = TraceEvent.scoped("BackgroundTaskScheduler.reschedule")) { ThreadUtils.assertOnUiThread(); - Set<String> scheduledTasksClassNames = BackgroundTaskSchedulerPrefs.getScheduledTasks(); + Set<Integer> scheduledTaskIds = BackgroundTaskSchedulerPrefs.getScheduledTaskIds(); BackgroundTaskSchedulerPrefs.removeAllTasks(); - for (String className : scheduledTasksClassNames) { - BackgroundTask task = - BackgroundTaskReflection.getBackgroundTaskFromClassName(className); - if (task == null) { - Log.w(TAG, "Cannot reschedule task for: " + className); + for (int taskId : scheduledTaskIds) { + final BackgroundTask backgroundTask = + BackgroundTaskSchedulerFactory.getBackgroundTaskFromTaskId(taskId); + if (backgroundTask == null) { + Log.w(TAG, + "Cannot reschedule task for task id " + taskId + ". Could not " + + "instantiate BackgroundTask class."); + // Cancel task if the BackgroundTask class is not found anymore. We assume this + // means that the task has been deprecated. + BackgroundTaskSchedulerFactory.getScheduler().cancel( + ContextUtils.getApplicationContext(), taskId); continue; } - task.reschedule(context); + backgroundTask.reschedule(context); } } }
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java index 68d5299..af6b9ef 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerJobService.java
@@ -40,17 +40,6 @@ sClock = clock; } - static BackgroundTask getBackgroundTaskFromJobParameters(JobParameters jobParameters) { - String backgroundTaskClassName = getBackgroundTaskClassFromJobParameters(jobParameters); - return BackgroundTaskReflection.getBackgroundTaskFromClassName(backgroundTaskClassName); - } - - private static String getBackgroundTaskClassFromJobParameters(JobParameters jobParameters) { - PersistableBundle extras = jobParameters.getExtras(); - if (extras == null) return null; - return extras.getString(BACKGROUND_TASK_CLASS_KEY); - } - static Long getDeadlineTimeFromJobParameters(JobParameters jobParameters) { PersistableBundle extras = jobParameters.getExtras(); if (extras == null || !extras.containsKey(BACKGROUND_TASK_DEADLINE_KEY)) { @@ -89,7 +78,6 @@ @VisibleForTesting static JobInfo createJobInfoFromTaskInfo(Context context, TaskInfo taskInfo) { PersistableBundle jobExtras = new PersistableBundle(); - jobExtras.putString(BACKGROUND_TASK_CLASS_KEY, taskInfo.getBackgroundTaskClass().getName()); if (!taskInfo.isPeriodic() && taskInfo.getOneOffInfo().expiresAfterWindowEndTime()) { jobExtras.putLong(BACKGROUND_TASK_DEADLINE_KEY, getDeadlineTime(taskInfo)); @@ -160,12 +148,6 @@ @Override public boolean schedule(Context context, TaskInfo taskInfo) { ThreadUtils.assertOnUiThread(); - if (!BackgroundTaskReflection.hasParameterlessPublicConstructor( - taskInfo.getBackgroundTaskClass())) { - Log.e(TAG, "BackgroundTask " + taskInfo.getBackgroundTaskClass() - + " has no parameterless public constructor."); - return false; - } JobInfo jobInfo = createJobInfoFromTaskInfo(context, taskInfo);
diff --git a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java index 54199d7..8229aae0 100644 --- a/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java +++ b/components/background_task_scheduler/android/java/src/org/chromium/components/background_task_scheduler/TaskIds.java
@@ -10,7 +10,9 @@ */ public final class TaskIds { // When adding your job id to the list below, remember to make a corresponding update to the - // BackgroundTaskSchedulerUma#toUmaEnumValueFromTaskId(int) method. + // BackgroundTaskSchedulerUma#toUmaEnumValueFromTaskId(int) method. Also, if the new task id + // is related to a BackgroundTask class in //chrome, remember to update + // ChromeBackgroundTaskFactory#getBackgroundTaskFromTaskId(int). public static final int TEST = 0x00008378; public static final int OMAHA_JOB_ID = 0x00011684;
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskServiceTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskServiceTest.java index 7a44dfd..f2b3daa 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskServiceTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskGcmTaskServiceTest.java
@@ -26,6 +26,7 @@ import org.robolectric.annotation.Config; import org.robolectric.util.ReflectionHelpers; +import org.chromium.base.ContextUtils; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Feature; @@ -44,6 +45,8 @@ private BackgroundTaskSchedulerDelegate mDelegate; @Mock private BackgroundTaskSchedulerUma mBackgroundTaskSchedulerUma; + @Mock + private BackgroundTaskSchedulerImpl mBackgroundTaskSchedulerImpl; @Before public void setUp() { @@ -76,15 +79,22 @@ } } - private static class TestBackgroundTaskNoPublicConstructor extends TestBackgroundTask {} + public class TestBackgroundTaskWithParamsFactory implements BackgroundTaskFactory { + @Override + public BackgroundTask getBackgroundTaskFromTaskId(int taskId) { + return new TestBackgroundTaskWithParams(); + } + } @Test @Feature({"BackgroundTaskScheduler"}) public void testStartsAnytimeWithoutDeadline() { + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new TestBackgroundTaskWithParamsFactory()); + Bundle taskExtras = new Bundle(); taskExtras.putString("foo", "bar"); - TaskParams taskParams = - buildTaskParams(TestBackgroundTaskWithParams.class, taskExtras, null); + TaskParams taskParams = buildTaskParams(TaskIds.TEST, taskExtras, null); BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); assertEquals(taskService.onRunTask(taskParams), GcmNetworkManager.RESULT_SUCCESS); @@ -101,8 +111,11 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testDoesNotStartExactlyAtDeadline() { - TaskParams taskParams = buildTaskParams( - TestBackgroundTaskWithParams.class, new Bundle(), sClock.currentTimeMillis()); + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new TestBackgroundTaskWithParamsFactory()); + + TaskParams taskParams = + buildTaskParams(TaskIds.TEST, new Bundle(), sClock.currentTimeMillis()); BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); taskService.setClockForTesting(sClock); @@ -116,8 +129,11 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testDoesNotStartAfterDeadline() { - TaskParams taskParams = buildTaskParams( - TestBackgroundTaskWithParams.class, new Bundle(), sZeroClock.currentTimeMillis()); + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new TestBackgroundTaskWithParamsFactory()); + + TaskParams taskParams = + buildTaskParams(TaskIds.TEST, new Bundle(), sZeroClock.currentTimeMillis()); BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); taskService.setClockForTesting(sClock); @@ -131,8 +147,11 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testStartsBeforeDeadline() { - TaskParams taskParams = buildTaskParams( - TestBackgroundTaskWithParams.class, new Bundle(), sClock.currentTimeMillis()); + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new TestBackgroundTaskWithParamsFactory()); + + TaskParams taskParams = + buildTaskParams(TaskIds.TEST, new Bundle(), sClock.currentTimeMillis()); BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); taskService.setClockForTesting(sZeroClock); @@ -148,21 +167,13 @@ @Test @Feature({"BackgroundTaskScheduler"}) - public void testOnRunTaskMissingConstructor() { - TaskParams taskParams = - buildTaskParams(TestBackgroundTaskNoPublicConstructor.class, new Bundle(), null); - - BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); - assertEquals(taskService.onRunTask(taskParams), GcmNetworkManager.RESULT_FAILURE); - } - - @Test - @Feature({"BackgroundTaskScheduler"}) public void testOnRuntaskNeedsReschedulingFromCallback() { + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new TestBackgroundTaskWithParamsFactory()); + sReturnThroughCallback = true; sNeedsRescheduling = true; - TaskParams taskParams = - buildTaskParams(TestBackgroundTaskWithParams.class, new Bundle(), null); + TaskParams taskParams = buildTaskParams(TaskIds.TEST, new Bundle(), null); BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); assertEquals(taskService.onRunTask(taskParams), GcmNetworkManager.RESULT_RESCHEDULE); @@ -171,10 +182,12 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testOnRuntaskDontRescheduleFromCallback() { + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory( + new TestBackgroundTaskWithParamsFactory()); + sReturnThroughCallback = true; sNeedsRescheduling = false; - TaskParams taskParams = - buildTaskParams(TestBackgroundTaskWithParams.class, new Bundle(), null); + TaskParams taskParams = buildTaskParams(TaskIds.TEST, new Bundle(), null); BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); assertEquals(taskService.onRunTask(taskParams), GcmNetworkManager.RESULT_SUCCESS); @@ -183,6 +196,8 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testOnInitializeTasksOnPreM() { + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); + ReflectionHelpers.setStaticField( Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.LOLLIPOP); TaskInfo task = TaskInfo.createOneOffTask(TaskIds.TEST, TestBackgroundTask.class, @@ -198,6 +213,8 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testOnInitializeTasksOnMPlus() { + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); + ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT", Build.VERSION_CODES.M); TaskInfo task = TaskInfo.createOneOffTask(TaskIds.TEST, TestBackgroundTask.class, TimeUnit.DAYS.toMillis(1)) @@ -209,17 +226,35 @@ assertEquals(0, TestBackgroundTask.getRescheduleCalls()); } - private static TaskParams buildTaskParams(Class clazz, Bundle taskExtras, Long deadlineTimeMs) { + @Test + @Feature({"BackgroundTaskScheduler"}) + public void testCancelTaskIfTaskIdNotFound() { + BackgroundTaskSchedulerFactory.setSchedulerForTesting(mBackgroundTaskSchedulerImpl); + + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); + + TaskParams taskParams = buildTaskParams( + TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID, new Bundle(), sClock.currentTimeMillis()); + + BackgroundTaskGcmTaskService taskService = new BackgroundTaskGcmTaskService(); + taskService.setClockForTesting(sZeroClock); + assertEquals(GcmNetworkManager.RESULT_FAILURE, taskService.onRunTask(taskParams)); + + verify(mBackgroundTaskSchedulerImpl, times(1)) + .cancel(eq(ContextUtils.getApplicationContext()), + eq(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)); + assertEquals(0, TestBackgroundTask.getRescheduleCalls()); + } + + private static TaskParams buildTaskParams(int taskId, Bundle taskExtras, Long deadlineTimeMs) { Bundle extras = new Bundle(); extras.putBundle( BackgroundTaskSchedulerGcmNetworkManager.BACKGROUND_TASK_EXTRAS_KEY, taskExtras); - extras.putString(BackgroundTaskSchedulerGcmNetworkManager.BACKGROUND_TASK_CLASS_KEY, - clazz.getName()); if (deadlineTimeMs != null) { extras.putLong(BackgroundTaskSchedulerGcmNetworkManager.BACKGROUND_TASK_DEADLINE_KEY, deadlineTimeMs); } - return new TaskParams(Integer.toString(TaskIds.TEST), extras); + return new TaskParams(Integer.toString(taskId), extras); } }
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobServiceTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobServiceTest.java index 6bfcfc2..4502d58 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobServiceTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskJobServiceTest.java
@@ -20,6 +20,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; +import org.chromium.base.ContextUtils; import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.util.Feature; @@ -33,6 +34,8 @@ private BackgroundTaskSchedulerDelegate mDelegate; @Mock private BackgroundTaskSchedulerUma mBackgroundTaskSchedulerUma; + @Mock + private BackgroundTaskSchedulerImpl mBackgroundTaskSchedulerImpl; @Before public void setUp() { @@ -41,12 +44,13 @@ new BackgroundTaskSchedulerImpl(mDelegate)); BackgroundTaskSchedulerUma.setInstanceForTesting(mBackgroundTaskSchedulerUma); TestBackgroundTask.reset(); + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); } @Test @Feature({"BackgroundTaskScheduler"}) public void testTaskStartsAnytimeWithoutDeadline() { - JobParameters jobParameters = buildJobParameters(null); + JobParameters jobParameters = buildJobParameters(TaskIds.TEST, null); BackgroundTaskJobService jobService = new BackgroundTaskJobService(); assertFalse(jobService.onStartJob(jobParameters)); @@ -58,7 +62,7 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testTaskDoesNotStartExactlyAtDeadline() { - JobParameters jobParameters = buildJobParameters(sClock.currentTimeMillis()); + JobParameters jobParameters = buildJobParameters(TaskIds.TEST, sClock.currentTimeMillis()); BackgroundTaskJobService jobService = new BackgroundTaskJobService(); jobService.setClockForTesting(sClock); @@ -71,7 +75,8 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testTaskDoesNotStartAfterDeadline() { - JobParameters jobParameters = buildJobParameters(sZeroClock.currentTimeMillis()); + JobParameters jobParameters = + buildJobParameters(TaskIds.TEST, sZeroClock.currentTimeMillis()); BackgroundTaskJobService jobService = new BackgroundTaskJobService(); jobService.setClockForTesting(sClock); @@ -84,7 +89,7 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testTaskStartsBeforeDeadline() { - JobParameters jobParameters = buildJobParameters(sClock.currentTimeMillis()); + JobParameters jobParameters = buildJobParameters(TaskIds.TEST, sClock.currentTimeMillis()); BackgroundTaskJobService jobService = new BackgroundTaskJobService(); jobService.setClockForTesting(sZeroClock); @@ -94,10 +99,26 @@ assertEquals(0, TestBackgroundTask.getRescheduleCalls()); } - private static JobParameters buildJobParameters(Long deadlineTime) { + @Test + @Feature({"BackgroundTaskScheduler"}) + public void testCancelTaskIfTaskIdNotFound() { + BackgroundTaskSchedulerFactory.setSchedulerForTesting(mBackgroundTaskSchedulerImpl); + + JobParameters jobParameters = buildJobParameters( + TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID, sClock.currentTimeMillis()); + + BackgroundTaskJobService jobService = new BackgroundTaskJobService(); + jobService.setClockForTesting(sZeroClock); + assertFalse(jobService.onStartJob(jobParameters)); + + verify(mBackgroundTaskSchedulerImpl, times(1)) + .cancel(eq(ContextUtils.getApplicationContext()), + eq(TaskIds.OFFLINE_PAGES_BACKGROUND_JOB_ID)); + assertEquals(0, TestBackgroundTask.getRescheduleCalls()); + } + + private static JobParameters buildJobParameters(int taskId, Long deadlineTime) { PersistableBundle extras = new PersistableBundle(); - extras.putString(BackgroundTaskSchedulerJobService.BACKGROUND_TASK_CLASS_KEY, - TestBackgroundTask.class.getName()); if (deadlineTime != null) { extras.putLong( BackgroundTaskSchedulerJobService.BACKGROUND_TASK_DEADLINE_KEY, deadlineTime); @@ -106,9 +127,9 @@ extras.putPersistableBundle( BackgroundTaskSchedulerJobService.BACKGROUND_TASK_EXTRAS_KEY, taskExtras); - return new JobParameters(null /* callback */, TaskIds.TEST, extras, - null /* transientExtras */, null /* clipData */, 0 /* clipGrantFlags */, - false /* overrideDeadlineExpired */, null /* triggeredContentUris */, - null /* triggeredContentAuthorities */, null /* network */); + return new JobParameters(null /* callback */, taskId, extras, null /* transientExtras */, + null /* clipData */, 0 /* clipGrantFlags */, false /* overrideDeadlineExpired */, + null /* triggeredContentUris */, null /* triggeredContentAuthorities */, + null /* network */); } } \ No newline at end of file
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManagerTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManagerTest.java index e177fdd..9f38603 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManagerTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerGcmNetworkManagerTest.java
@@ -39,10 +39,6 @@ @Config(manifest = Config.NONE, shadows = {ShadowGcmNetworkManager.class, ShadowGoogleApiAvailability.class}) public class BackgroundTaskSchedulerGcmNetworkManagerTest { - private static class TestBackgroundTaskNoPublicConstructor extends TestBackgroundTask { - protected TestBackgroundTaskNoPublicConstructor() {} - } - ShadowGcmNetworkManager mGcmNetworkManager; private static final long CLOCK_TIME_MS = 1415926535000L; @@ -225,13 +221,11 @@ @Test @Feature({"BackgroundTaskScheduler"}) public void testGetBackgroundTaskFromTaskParams() { - Bundle extras = new Bundle(); - extras.putString(BackgroundTaskSchedulerGcmNetworkManager.BACKGROUND_TASK_CLASS_KEY, - TestBackgroundTask.class.getName()); + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); - TaskParams params = new TaskParams(Integer.toString(TaskIds.TEST), extras); - BackgroundTask backgroundTask = - BackgroundTaskSchedulerGcmNetworkManager.getBackgroundTaskFromTaskParams(params); + TaskParams params = new TaskParams(Integer.toString(TaskIds.TEST), new Bundle()); + BackgroundTask backgroundTask = BackgroundTaskSchedulerFactory.getBackgroundTaskFromTaskId( + Integer.valueOf(params.getTag())); assertNotNull(backgroundTask); assertTrue(backgroundTask instanceof TestBackgroundTask); @@ -265,18 +259,6 @@ @Test @Feature("BackgroundTaskScheduler") - public void testScheduleNoPublicConstructor() { - TaskInfo oneOffTaskInfo = - TaskInfo.createOneOffTask(TaskIds.TEST, TestBackgroundTaskNoPublicConstructor.class, - TIME_24_H_TO_MS) - .build(); - - assertFalse(new BackgroundTaskSchedulerGcmNetworkManager().schedule( - ContextUtils.getApplicationContext(), oneOffTaskInfo)); - } - - @Test - @Feature("BackgroundTaskScheduler") public void testScheduleNoGooglePlayServices() { Shadows.shadowOf(GoogleApiAvailability.getInstance()) .setIsGooglePlayServicesAvailable(ConnectionResult.SERVICE_MISSING);
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplTest.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplTest.java index 91864639..4dccb4f8 100644 --- a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplTest.java +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/BackgroundTaskSchedulerImplTest.java
@@ -72,6 +72,7 @@ TimeUnit.DAYS.toMillis(1)) .setExpiresAfterWindowEndTime(true) .build(); + BackgroundTaskSchedulerFactory.setBackgroundTaskFactory(new TestBackgroundTaskFactory()); } @Test
diff --git a/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TestBackgroundTaskFactory.java b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TestBackgroundTaskFactory.java new file mode 100644 index 0000000..596a8c5 --- /dev/null +++ b/components/background_task_scheduler/android/junit/src/org/chromium/components/background_task_scheduler/TestBackgroundTaskFactory.java
@@ -0,0 +1,19 @@ +// 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.components.background_task_scheduler; + +/** + * Implementation of {@link BackgroundTaskFactory} for testing. + * The default {@link TestBackgroundTask} class is used. + */ +public class TestBackgroundTaskFactory implements BackgroundTaskFactory { + @Override + public BackgroundTask getBackgroundTaskFromTaskId(int taskId) { + if (taskId == TaskIds.TEST) { + return new TestBackgroundTask(); + } + return null; + } +}
diff --git a/components/content_settings/core/browser/cookie_settings.cc b/components/content_settings/core/browser/cookie_settings.cc index 44b4fc0..5de7efb 100644 --- a/components/content_settings/core/browser/cookie_settings.cc +++ b/components/content_settings/core/browser/cookie_settings.cc
@@ -17,8 +17,6 @@ #include "components/pref_registry/pref_registry_syncable.h" #include "components/prefs/pref_service.h" #include "extensions/buildflags/buildflags.h" -#include "net/base/net_errors.h" -#include "net/base/static_cookie_policy.h" #include "url/gurl.h" namespace content_settings { @@ -123,10 +121,12 @@ pref_change_registrar_.RemoveAll(); } -void CookieSettings::GetCookieSetting(const GURL& url, - const GURL& first_party_url, - content_settings::SettingSource* source, - ContentSetting* cookie_setting) const { +void CookieSettings::GetCookieSettingInternal( + const GURL& url, + const GURL& first_party_url, + bool is_third_party_request, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const { DCHECK(cookie_setting); // Auto-allow in extensions or for WebUI embedded in a secure origin. if (first_party_url.SchemeIs(kChromeUIScheme) && @@ -158,14 +158,11 @@ info.secondary_pattern.MatchesAllHosts() && ShouldBlockThirdPartyCookies() && !first_party_url.SchemeIs(extension_scheme_); - net::StaticCookiePolicy policy( - net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES); // We should always have a value, at least from the default provider. DCHECK(value); ContentSetting setting = ValueToContentSetting(value.get()); - bool block = - block_third && policy.CanAccessCookies(url, first_party_url) != net::OK; + bool block = block_third && is_third_party_request; *cookie_setting = block ? CONTENT_SETTING_BLOCK : setting; }
diff --git a/components/content_settings/core/browser/cookie_settings.h b/components/content_settings/core/browser/cookie_settings.h index 481987c..941ea0a 100644 --- a/components/content_settings/core/browser/cookie_settings.h +++ b/components/content_settings/core/browser/cookie_settings.h
@@ -107,12 +107,6 @@ // called. void ShutdownOnUIThread() override; - // content_settings::CookieSettingsBase: - void GetCookieSetting(const GURL& url, - const GURL& first_party_url, - content_settings::SettingSource* source, - ContentSetting* cookie_setting) const override; - static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); void AddObserver(Observer* obs) { observers_.AddObserver(obs); } @@ -122,6 +116,13 @@ private: ~CookieSettings() override; + // content_settings::CookieSettingsBase: + void GetCookieSettingInternal(const GURL& url, + const GURL& first_party_url, + bool is_third_party_request, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const override; + void OnCookiePreferencesChanged(); base::ThreadChecker thread_checker_;
diff --git a/components/content_settings/core/common/BUILD.gn b/components/content_settings/core/common/BUILD.gn index f396acdb2..78123bb0 100644 --- a/components/content_settings/core/common/BUILD.gn +++ b/components/content_settings/core/common/BUILD.gn
@@ -18,14 +18,16 @@ "content_settings_utils.h", "cookie_settings_base.cc", "cookie_settings_base.h", - "features.cc", - "features.h", "pref_names.cc", "pref_names.h", ] configs += [ "//build/config/compiler:wexit_time_destructors" ] + public_deps = [ + ":features", + ] + deps = [ "//base", "//mojo/public/cpp/base", @@ -62,3 +64,18 @@ "//mojo/public/mojom/base", ] } + +component("features") { + output_name = "content_settings_features" + + defines = [ "IS_CONTENT_SETTINGS_FEATURES_IMPL" ] + + sources = [ + "features.cc", + "features.h", + ] + + deps = [ + "//base", + ] +}
diff --git a/components/content_settings/core/common/cookie_settings_base.cc b/components/content_settings/core/common/cookie_settings_base.cc index e4909a9..e3fb559 100644 --- a/components/content_settings/core/common/cookie_settings_base.cc +++ b/components/content_settings/core/common/cookie_settings_base.cc
@@ -3,10 +3,23 @@ // found in the LICENSE file. #include "components/content_settings/core/common/cookie_settings_base.h" +#include "base/debug/stack_trace.h" +#include "base/debug/task_trace.h" +#include "base/feature_list.h" +#include "components/content_settings/core/common/features.h" +#include "net/base/net_errors.h" +#include "net/base/static_cookie_policy.h" #include "net/cookies/cookie_util.h" #include "url/gurl.h" namespace content_settings { +namespace { +bool IsThirdPartyRequest(const GURL& url, const GURL& site_for_cookies) { + net::StaticCookiePolicy policy( + net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES); + return policy.CanAccessCookies(url, site_for_cookies) != net::OK; +} +} // namespace bool CookieSettingsBase::ShouldDeleteCookieOnExit( const ContentSettingsForOneType& cookie_settings, @@ -38,14 +51,44 @@ return setting == CONTENT_SETTING_SESSION_ONLY || matches_session_only_rule; } +void CookieSettingsBase::GetCookieSetting( + const GURL& url, + const GURL& first_party_url, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const { + GetCookieSettingInternal(url, first_party_url, + IsThirdPartyRequest(url, first_party_url), source, + cookie_setting); +} + bool CookieSettingsBase::IsCookieAccessAllowed( const GURL& url, const GURL& first_party_url) const { + DCHECK(!base::FeatureList::IsEnabled(kImprovedCookieControls) || + !first_party_url.is_empty() || url.is_empty()); ContentSetting setting; GetCookieSetting(url, first_party_url, nullptr, &setting); return IsAllowed(setting); } +bool CookieSettingsBase::IsCookieAccessAllowed( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const { + // TODO(crbug.com/988398): top_frame_origin is not yet always available. + // Ensure that the DCHECK always passes and remove the FeatureList check. + if (!base::FeatureList::IsEnabled(kImprovedCookieControls)) + return IsCookieAccessAllowed(url, site_for_cookies); + DCHECK(top_frame_origin || site_for_cookies.is_empty()) + << url << " " << site_for_cookies; + + ContentSetting setting; + GetCookieSettingInternal( + url, top_frame_origin ? top_frame_origin->GetURL() : GURL(), + IsThirdPartyRequest(url, site_for_cookies), nullptr, &setting); + return IsAllowed(setting); +} + bool CookieSettingsBase::IsCookieSessionOnly(const GURL& origin) const { ContentSetting setting; GetCookieSetting(origin, origin, nullptr, &setting);
diff --git a/components/content_settings/core/common/cookie_settings_base.h b/components/content_settings/core/common/cookie_settings_base.h index e2318177..e9b045c 100644 --- a/components/content_settings/core/common/cookie_settings_base.h +++ b/components/content_settings/core/common/cookie_settings_base.h
@@ -7,10 +7,53 @@ #include <string> +#include "base/optional.h" #include "components/content_settings/core/common/content_settings.h" +namespace url { +class Origin; +} + namespace content_settings { +// Many CookieSettings methods handle the parameters |url|, |site_for_cookies| +// |top_frame_origin| and |first_party_url|. +// +// |url| is the URL of the requested resource. +// |site_for_cookies| is usually the URL shown in the omnibox but can also be +// empty, e.g. for subresource loads initiated from cross-site iframes, and is +// used to determine if a request is done in a third-party context. +// |top_frame_origin| is the origin shown in the omnibox. +// +// Example: +// https://a.com/index.html +// <html> +// <body> +// <iframe href="https://b.com/frame.html"> +// <img href="https://a.com/img.jpg> +// <img href="https://b.com/img.jpg> +// <img href="https://c.com/img.jpg> +// </iframe> +// </body> +// </html> +// +// When each of these resources get fetched, |top_frame_origin| will always be +// "https://a.com" and |site_for_cookies| is set the following: +// https://a.com/index.html -> https://a.com/ (1p request) +// https://b.com/frame.html -> https://a.com/ (3p request) +// https://a.com/img.jpg -> <empty-url> (treated as 3p request) +// https://b.com/img.jpg -> <empty-url> (3p because from cross site iframe) +// https://c.com/img.jpg -> <empty-url> (3p request in cross site iframe) +// +// Content settings can be used to allow or block access to cookies. +// When third-party cookies are blocked, an ALLOW setting will give access to +// cookies in third-party contexts. +// The primary pattern of each setting is matched against |url|. +// The secondary pattern is matched against |top_frame_origin|. +// +// Some methods only take |url| and |first_party_url|. For |first_party_url|, +// clients either pass a value that is like |site_for_cookies| or +// |top_frame_origin|. This is done inconsistently and needs to be fixed. class CookieSettingsBase { public: CookieSettingsBase() = default; @@ -31,12 +74,25 @@ bool is_https) const; // Returns true if the page identified by (|url|, |first_party_url|) is - // allowed to access (i.e., read or write) cookies. + // allowed to access (i.e., read or write) cookies. |first_party_url| + // is used to determine third-party-ness of |url|. // // This may be called on any thread. + // DEPRECATED: Replace with IsCookieAccessAllowed(GURL, GURL, Origin). bool IsCookieAccessAllowed(const GURL& url, const GURL& first_party_url) const; + // Similar to IsCookieAccessAllowed(GURL, GURL) but provides a mechanism + // to specify a separate |site_for_cookies|, which is used to determine + // whether a request is in a third_party context and |top_frame_origin|, which + // is used to check if there are any content_settings exceptions. + // |top_frame_origin| should at least be specified when |site_for_cookies| is + // non-empty. + bool IsCookieAccessAllowed( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const; + // Returns true if the cookie set by a page identified by |url| should be // session only. Querying this only makes sense if |IsCookieAccessAllowed| // has returned true. @@ -45,10 +101,10 @@ bool IsCookieSessionOnly(const GURL& url) const; // A helper for applying third party cookie blocking rules. - virtual void GetCookieSetting(const GURL& url, - const GURL& first_party_url, - content_settings::SettingSource* source, - ContentSetting* cookie_setting) const = 0; + void GetCookieSetting(const GURL& url, + const GURL& first_party_url, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const; // Determines whether |setting| is a valid content setting for cookies. static bool IsValidSetting(ContentSetting setting); @@ -56,6 +112,13 @@ static bool IsAllowed(ContentSetting setting); private: + virtual void GetCookieSettingInternal( + const GURL& url, + const GURL& first_party_url, + bool is_third_party_request, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const = 0; + DISALLOW_COPY_AND_ASSIGN(CookieSettingsBase); };
diff --git a/components/content_settings/core/common/cookie_settings_base_unittest.cc b/components/content_settings/core/common/cookie_settings_base_unittest.cc index 0d960de..71df422 100644 --- a/components/content_settings/core/common/cookie_settings_base_unittest.cc +++ b/components/content_settings/core/common/cookie_settings_base_unittest.cc
@@ -29,10 +29,11 @@ : callback_(std::move(callback)) {} // CookieSettingsBase: - void GetCookieSetting(const GURL& url, - const GURL& first_party_url, - content_settings::SettingSource* source, - ContentSetting* cookie_setting) const override { + void GetCookieSettingInternal(const GURL& url, + const GURL& first_party_url, + bool is_third_party_request, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const override { *cookie_setting = callback_.Run(url); } @@ -102,37 +103,37 @@ TEST(CookieSettingsBaseTest, CookieAccessNotAllowedWithBlockedSetting) { CallbackCookieSettings settings( base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; })); - EXPECT_FALSE(settings.IsCookieAccessAllowed(GURL(), GURL())); + EXPECT_FALSE(settings.IsCookieAccessAllowed(GURL(kDomain), GURL(kDomain))); } TEST(CookieSettingsBaseTest, CookieAccessAllowedWithAllowSetting) { CallbackCookieSettings settings( base::BindRepeating([](const GURL&) { return CONTENT_SETTING_ALLOW; })); - EXPECT_TRUE(settings.IsCookieAccessAllowed(GURL(), GURL())); + EXPECT_TRUE(settings.IsCookieAccessAllowed(GURL(kDomain), GURL(kDomain))); } TEST(CookieSettingsBaseTest, CookieAccessAllowedWithSessionOnlySetting) { CallbackCookieSettings settings(base::BindRepeating( [](const GURL&) { return CONTENT_SETTING_SESSION_ONLY; })); - EXPECT_TRUE(settings.IsCookieAccessAllowed(GURL(), GURL())); + EXPECT_TRUE(settings.IsCookieAccessAllowed(GURL(kDomain), GURL(kDomain))); } TEST(CookieSettingsBaseTest, IsCookieSessionOnlyWithAllowSetting) { CallbackCookieSettings settings( base::BindRepeating([](const GURL&) { return CONTENT_SETTING_ALLOW; })); - EXPECT_FALSE(settings.IsCookieSessionOnly(GURL())); + EXPECT_FALSE(settings.IsCookieSessionOnly(GURL(kDomain))); } TEST(CookieSettingsBaseTest, IsCookieSessionOnlyWithBlockSetting) { CallbackCookieSettings settings( base::BindRepeating([](const GURL&) { return CONTENT_SETTING_BLOCK; })); - EXPECT_FALSE(settings.IsCookieSessionOnly(GURL())); + EXPECT_FALSE(settings.IsCookieSessionOnly(GURL(kDomain))); } TEST(CookieSettingsBaseTest, IsCookieSessionOnlySessionWithOnlySetting) { CallbackCookieSettings settings(base::BindRepeating( [](const GURL&) { return CONTENT_SETTING_SESSION_ONLY; })); - EXPECT_TRUE(settings.IsCookieSessionOnly(GURL())); + EXPECT_TRUE(settings.IsCookieSessionOnly(GURL(kDomain))); } TEST(CookieSettingsBaseTest, IsValidSetting) {
diff --git a/components/content_settings/core/common/features.h b/components/content_settings/core/common/features.h index 817b2f1c..846d495 100644 --- a/components/content_settings/core/common/features.h +++ b/components/content_settings/core/common/features.h
@@ -5,6 +5,8 @@ #ifndef COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_FEATURES_H_ #define COMPONENTS_CONTENT_SETTINGS_CORE_COMMON_FEATURES_H_ +#include "base/component_export.h" + namespace base { struct Feature; } // namespace base @@ -12,6 +14,7 @@ namespace content_settings { // Feature to enable a better cookie controls ui. +COMPONENT_EXPORT(CONTENT_SETTINGS_FEATURES) extern const base::Feature kImprovedCookieControls; } // namespace content_settings
diff --git a/components/offline_pages/core/model/offline_page_model_utils.cc b/components/offline_pages/core/model/offline_page_model_utils.cc index 6785f1a..d0783e52 100644 --- a/components/offline_pages/core/model/offline_page_model_utils.cc +++ b/components/offline_pages/core/model/offline_page_model_utils.cc
@@ -74,8 +74,7 @@ title, url, false /* can_save_as_complete */, kMHTMLMimeType)); // Find a unique name based on |suggested_path|. - int uniquifier = - base::GetUniquePathNumber(suggested_path, base::FilePath::StringType()); + int uniquifier = base::GetUniquePathNumber(suggested_path); base::FilePath::StringType suffix; if (uniquifier > 0) #if defined(OS_WIN)
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc index 6f1cc59..b0b4289a 100644 --- a/components/password_manager/core/browser/new_password_form_manager.cc +++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -742,6 +742,12 @@ #endif } +#if defined(OS_IOS) + // Filling on username first flow is not supported on iOS. + if (observed_password_form->IsSingleUsername()) + return; +#endif + SendFillInformationToRenderer(client_, driver_.get(), IsBlacklisted(), *observed_password_form.get(), best_matches_, form_fetcher_->GetFederatedMatches(),
diff --git a/components/password_manager/core/browser/password_form_filling.cc b/components/password_manager/core/browser/password_form_filling.cc index 02531a90..d8d60b1 100644 --- a/components/password_manager/core/browser/password_form_filling.cc +++ b/components/password_manager/core/browser/password_form_filling.cc
@@ -141,7 +141,8 @@ // current password field, no filling attempt will be made. In this case the // renderer won't treat this as the "first filling" and won't record metrics // accordingly. The browser should not do that either. - const bool no_sign_in_form = !observed_form.HasPasswordElement(); + const bool no_sign_in_form = + !observed_form.HasPasswordElement() && !observed_form.IsSingleUsername(); // Wait for the username before filling passwords in case the // FillOnAccountSelectHttp feature is active and the main frame is
diff --git a/components/password_manager/core/browser/password_form_filling_unittest.cc b/components/password_manager/core/browser/password_form_filling_unittest.cc index f13c7778..39147e8 100644 --- a/components/password_manager/core/browser/password_form_filling_unittest.cc +++ b/components/password_manager/core/browser/password_form_filling_unittest.cc
@@ -63,7 +63,9 @@ observed_form_.origin = GURL("http://accounts.google.com/a/LoginAuth"); observed_form_.action = GURL("http://accounts.google.com/a/Login"); observed_form_.username_element = ASCIIToUTF16("Email"); + observed_form_.username_element_renderer_id = 100; observed_form_.password_element = ASCIIToUTF16("Passwd"); + observed_form_.password_element_renderer_id = 101; observed_form_.submit_element = ASCIIToUTF16("signIn"); observed_form_.signon_realm = "http://accounts.google.com"; observed_form_.form_data.name = ASCIIToUTF16("the-form-name"); @@ -180,9 +182,10 @@ best_matches[saved_match_.username_value] = &saved_match_; PasswordForm observed_form = observed_form_; - observed_form.password_element_renderer_id = 123; - if (!test_case.new_password_present) + if (test_case.new_password_present) { observed_form.new_password_element = ASCIIToUTF16("New Passwd"); + observed_form.new_password_element_renderer_id = 125; + } if (!test_case.current_password_present) { observed_form.password_element.clear(); observed_form.password_element_renderer_id =
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc index 78c0dbb2..e41a21c 100644 --- a/components/password_manager/core/browser/password_manager_unittest.cc +++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -3910,16 +3910,20 @@ FormStructure form_structure(form_data); form_structure.field(0)->set_server_type(autofill::SINGLE_USERNAME); +#if !defined(OS_IOS) PasswordFormFillData fill_data; EXPECT_CALL(driver_, FillPasswordForm(_)).WillOnce(SaveArg<0>(&fill_data)); manager()->ProcessAutofillPredictions(&driver_, {&form_structure}); EXPECT_EQ(form_id, fill_data.form_renderer_id); EXPECT_EQ(saved_match.username_value, fill_data.username_field.value); - EXPECT_EQ(saved_match.username_value, fill_data.username_field.value); + EXPECT_EQ(saved_match.password_value, fill_data.password_field.value); EXPECT_EQ(field_id, fill_data.username_field.unique_renderer_id); EXPECT_EQ(saved_match.password_value, fill_data.password_field.value); EXPECT_EQ(std::numeric_limits<uint32_t>::max(), fill_data.password_field.unique_renderer_id); +#else // defined(OS_IOS) + EXPECT_CALL(driver_, FillPasswordForm(_)).Times(0); +#endif // !defined(OS_IOS) } } // namespace password_manager
diff --git a/components/password_manager/core/browser/password_sync_util.cc b/components/password_manager/core/browser/password_sync_util.cc index 7d43c6e7..1827978 100644 --- a/components/password_manager/core/browser/password_sync_util.cc +++ b/components/password_manager/core/browser/password_sync_util.cc
@@ -50,7 +50,7 @@ bool IsSyncAccountCredential(const autofill::PasswordForm& form, const syncer::SyncService* sync_service, const signin::IdentityManager* identity_manager) { - if (!IsGaiaCredentialPage(form.signon_realm)) + if (!GURL(form.signon_realm).DomainIs("google.com")) return false; // The empty username can mean that Chrome did not detect it correctly. For
diff --git a/components/password_manager/core/browser/password_sync_util_unittest.cc b/components/password_manager/core/browser/password_sync_util_unittest.cc index af91600..9a02d6a 100644 --- a/components/password_manager/core/browser/password_sync_util_unittest.cc +++ b/components/password_manager/core/browser/password_sync_util_unittest.cc
@@ -7,6 +7,7 @@ #include <stddef.h> #include "base/stl_util.h" +#include "base/strings/utf_string_conversions.h" #include "build/build_config.h" #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/browser/sync_username_test_base.h" @@ -19,6 +20,7 @@ #endif // SYNC_PASSWORD_REUSE_DETECTION_ENABLED using autofill::PasswordForm; +using base::ASCIIToUTF16; namespace password_manager { namespace sync_util { @@ -31,6 +33,13 @@ return form; } +PasswordForm SimpleForm(const char* signon_realm, const char* username) { + PasswordForm form; + form.signon_realm = signon_realm; + form.username_value = ASCIIToUTF16(username); + return form; +} + TEST_F(PasswordSyncUtilTest, GetSyncUsernameIfSyncingPasswords) { const struct TestCase { enum { SYNCING_PASSWORDS, NOT_SYNCING_PASSWORDS } password_sync; @@ -82,6 +91,10 @@ {SimpleGaiaForm(""), "sync_user@example.org", true}, {SimpleNonGaiaForm(""), "sync_user@example.org", false}, {SimpleGAIAChangePasswordForm(), "sync_user@example.org", true}, + {SimpleForm("https://subdomain.google.com/", "sync_user@example.org"), + "sync_user@example.org", true}, + {SimpleForm("https://subdomain.google.com/", ""), "sync_user@example.org", + true}, }; for (size_t i = 0; i < base::size(kTestCases); ++i) {
diff --git a/components/printing/browser/print_manager.h b/components/printing/browser/print_manager.h index 3a146f5..c414e0d 100644 --- a/components/printing/browser/print_manager.h +++ b/components/printing/browser/print_manager.h
@@ -24,7 +24,7 @@ #if defined(OS_ANDROID) // TODO(timvolodine): consider introducing PrintManagerAndroid (crbug/500960) - using PdfWritingDoneCallback = base::Callback<void(int /* page count */)>; + using PdfWritingDoneCallback = base::OnceCallback<void(int /* page count */)>; virtual void PdfWritingDone(int page_count) = 0; #endif
diff --git a/components/sync/base/model_type.h b/components/sync/base/model_type.h index fee176f..489c10e 100644 --- a/components/sync/base/model_type.h +++ b/components/sync/base/model_type.h
@@ -219,8 +219,8 @@ // User types, which are not user-controlled. constexpr ModelTypeSet AlwaysPreferredUserTypes() { - return ModelTypeSet(DEVICE_INFO, USER_CONSENTS, SUPERVISED_USER_SETTINGS, - SUPERVISED_USER_WHITELISTS); + return ModelTypeSet(DEVICE_INFO, USER_CONSENTS, SECURITY_EVENTS, + SUPERVISED_USER_SETTINGS, SUPERVISED_USER_WHITELISTS); } // This is the subset of UserTypes() that have priority over other types. These
diff --git a/components/sync/base/user_selectable_type.cc b/components/sync/base/user_selectable_type.cc index 8dff9e0..df12e4d 100644 --- a/components/sync/base/user_selectable_type.cc +++ b/components/sync/base/user_selectable_type.cc
@@ -27,7 +27,8 @@ case UserSelectableType::kPreferences: return {"preferences", PREFERENCES, - {PREFERENCES, DICTIONARY, PRIORITY_PREFERENCES, SEARCH_ENGINES}}; + {PREFERENCES, DICTIONARY, PRIORITY_PREFERENCES, SEARCH_ENGINES, + PRINTERS}}; case UserSelectableType::kPasswords: return {"passwords", PASSWORDS, {PASSWORDS}}; case UserSelectableType::kAutofill:
diff --git a/components/sync/driver/sync_user_settings_unittest.cc b/components/sync/driver/sync_user_settings_unittest.cc index 6a54f3e..bfdcea9 100644 --- a/components/sync/driver/sync_user_settings_unittest.cc +++ b/components/sync/driver/sync_user_settings_unittest.cc
@@ -136,6 +136,7 @@ expected_preferred_types.Put(DICTIONARY); expected_preferred_types.Put(PRIORITY_PREFERENCES); expected_preferred_types.Put(SEARCH_ENGINES); + expected_preferred_types.Put(PRINTERS); } if (type == UserSelectableType::kApps) { expected_preferred_types.Put(APP_LIST);
diff --git a/content/browser/OWNERS b/content/browser/OWNERS index ef7a5bda..01b0227 100644 --- a/content/browser/OWNERS +++ b/content/browser/OWNERS
@@ -38,3 +38,6 @@ per-file builtin_service_manifests.cc=file://ipc/SECURITY_OWNERS per-file builtin_service_manifests.h=set noparent per-file builtin_service_manifests.h=file://ipc/SECURITY_OWNERS + +# BackForwardCache +per-file back_forward_cache_browsertest.cc=arthursonzogni@chromium.org
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc index 1b2340b1..3cc13a3 100644 --- a/content/browser/accessibility/browser_accessibility.cc +++ b/content/browser/accessibility/browser_accessibility.cc
@@ -20,7 +20,6 @@ #include "content/public/common/content_client.h" #include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_role_properties.h" -#include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/ax_tree_id.h" #include "ui/accessibility/platform/ax_unique_id.h" #include "ui/gfx/geometry/rect_conversions.h" @@ -43,7 +42,7 @@ namespace { int GetBoundaryTextOffsetInsideBaseAnchor( - ui::TextBoundaryDirection direction, + ui::AXTextBoundaryDirection direction, const BrowserAccessibilityPosition::AXPositionInstance& base, const BrowserAccessibilityPosition::AXPositionInstance& position) { if (base->GetAnchor() == position->GetAnchor()) @@ -52,9 +51,9 @@ // If the position is outside the anchor of the base position, then return // the first or last position in the same direction. switch (direction) { - case ui::BACKWARDS_DIRECTION: + case ui::AXTextBoundaryDirection::kBackwards: return base->CreatePositionAtStartOfAnchor()->text_offset(); - case ui::FORWARDS_DIRECTION: + case ui::AXTextBoundaryDirection::kForwards: return base->CreatePositionAtEndOfAnchor()->text_offset(); } } @@ -1316,64 +1315,29 @@ base::Optional<int> BrowserAccessibility::FindTextBoundary( ui::AXTextBoundary boundary, int offset, - ui::TextBoundaryDirection direction, + ui::AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) const { - switch (boundary) { - case ui::AXTextBoundary::kWordStart: { - BrowserAccessibilityPositionInstance position = - CreatePositionAt(static_cast<int>(offset), affinity); - switch (direction) { - case ui::BACKWARDS_DIRECTION: - return GetBoundaryTextOffsetInsideBaseAnchor( - direction, position, - position->CreatePreviousWordStartPosition( - ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)); - case ui::FORWARDS_DIRECTION: - return GetBoundaryTextOffsetInsideBaseAnchor( - direction, position, - position->CreateNextWordStartPosition( - ui::AXBoundaryBehavior::StopAtAnchorBoundary)); - } - } - case ui::AXTextBoundary::kWordStartOrEnd: { - BrowserAccessibilityPositionInstance position = - CreatePositionAt(static_cast<int>(offset), affinity); - switch (direction) { - case ui::BACKWARDS_DIRECTION: - return GetBoundaryTextOffsetInsideBaseAnchor( - direction, position, - position->CreatePreviousWordStartPosition( - ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)); - case ui::FORWARDS_DIRECTION: - return GetBoundaryTextOffsetInsideBaseAnchor( - direction, position, - position->CreateNextWordEndPosition( - ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)); - } - } - case ui::AXTextBoundary::kLineStart: { - BrowserAccessibilityPositionInstance position = - CreatePositionAt(static_cast<int>(offset), affinity); - switch (direction) { - case ui::BACKWARDS_DIRECTION: - return GetBoundaryTextOffsetInsideBaseAnchor( - direction, position, - position->CreatePreviousLineStartPosition( - ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary)); - case ui::FORWARDS_DIRECTION: - return GetBoundaryTextOffsetInsideBaseAnchor( - direction, position, - position->CreateNextLineStartPosition( - ui::AXBoundaryBehavior::StopAtAnchorBoundary)); - } - } - default: - // TODO(nektar): |AXPosition| can handle other types of boundaries as - // well. - return ui::FindAccessibleTextBoundary(GetHypertext(), - GetLineStartOffsets(), boundary, - offset, direction, affinity); + BrowserAccessibilityPositionInstance position = + CreatePositionAt(offset, affinity); + + // On Windows and Linux ATK, searching for a text boundary should always stop + // at the boundary of the current object. + auto boundary_behavior = ui::AXBoundaryBehavior::StopAtAnchorBoundary; + // On Windows and Linux ATK, it is standard text navigation behavior to stop + // if we are searching in the backwards direction and the current position is + // already at the required text boundary. + if (direction == ui::AXTextBoundaryDirection::kBackwards) { + // AXPosition disallows ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary when + // used on character boundaries because it would be non-sensical. + if (boundary == ui::AXTextBoundary::kCharacter) + return offset; + boundary_behavior = ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary; } + + return GetBoundaryTextOffsetInsideBaseAnchor( + direction, position, + position->CreatePositionAtTextBoundary(boundary, direction, + boundary_behavior)); } const std::vector<gfx::NativeViewAccessible>
diff --git a/content/browser/accessibility/browser_accessibility.h b/content/browser/accessibility/browser_accessibility.h index 407b99f7..172c578 100644 --- a/content/browser/accessibility/browser_accessibility.h +++ b/content/browser/accessibility/browser_accessibility.h
@@ -29,7 +29,6 @@ #include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_range.h" #include "ui/accessibility/ax_text_boundary.h" -#include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/accessibility/platform/ax_platform_node_delegate.h" @@ -478,7 +477,7 @@ base::Optional<int> FindTextBoundary( ui::AXTextBoundary boundary, int offset, - ui::TextBoundaryDirection direction, + ui::AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) const override; const std::vector<gfx::NativeViewAccessible> GetDescendants() const override;
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm index 61ec74b..eb17b696 100644 --- a/content/browser/accessibility/browser_accessibility_cocoa.mm +++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -2812,12 +2812,11 @@ return nil; BrowserAccessibilityPositionInstance startPosition = - position->CreatePositionAtFormatBoundary( - ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary, - /*forwards*/ false); + position->CreatePreviousFormatStartPosition( + ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary); BrowserAccessibilityPositionInstance endPosition = - position->CreatePositionAtFormatBoundary( - ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary, /*forwards*/ true); + position->CreateNextFormatEndPosition( + ui::AXBoundaryBehavior::StopIfAlreadyAtBoundary); AXPlatformRange range(std::move(startPosition), std::move(endPosition)); return CreateTextMarkerRange(std::move(range)); }
diff --git a/content/browser/accessibility/browser_accessibility_com_win.cc b/content/browser/accessibility/browser_accessibility_com_win.cc index 6432891..8fba7b5 100644 --- a/content/browser/accessibility/browser_accessibility_com_win.cc +++ b/content/browser/accessibility/browser_accessibility_com_win.cc
@@ -25,7 +25,6 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/accessibility/ax_mode.h" #include "ui/accessibility/ax_role_properties.h" -#include "ui/accessibility/ax_text_utils.h" #include "ui/base/win/accessibility_ids_win.h" #include "ui/base/win/accessibility_misc_utils.h" #include "ui/base/win/atl_module.h" @@ -356,8 +355,10 @@ if (offset == text_len && boundary_type != IA2_TEXT_BOUNDARY_LINE) return S_FALSE; - LONG start = FindIA2Boundary(boundary_type, offset, ui::BACKWARDS_DIRECTION); - LONG end = FindIA2Boundary(boundary_type, start, ui::FORWARDS_DIRECTION); + LONG start = FindIA2Boundary(boundary_type, offset, + ui::AXTextBoundaryDirection::kBackwards); + LONG end = FindIA2Boundary(boundary_type, start, + ui::AXTextBoundaryDirection::kForwards); if (end < offset) return S_FALSE; @@ -395,8 +396,8 @@ if (boundary_type == IA2_TEXT_BOUNDARY_SENTENCE) return S_FALSE; - *start_offset = - FindIA2Boundary(boundary_type, offset, ui::BACKWARDS_DIRECTION); + *start_offset = FindIA2Boundary(boundary_type, offset, + ui::AXTextBoundaryDirection::kBackwards); *end_offset = offset; return get_text(*start_offset, *end_offset, text); } @@ -431,7 +432,8 @@ return S_FALSE; *start_offset = offset; - *end_offset = FindIA2Boundary(boundary_type, offset, ui::FORWARDS_DIRECTION); + *end_offset = FindIA2Boundary(boundary_type, offset, + ui::AXTextBoundaryDirection::kForwards); return get_text(*start_offset, *end_offset, text); } @@ -600,8 +602,10 @@ return E_INVALIDARG; ComputeStylesIfNeeded(); - *start_offset = FindStartOfStyle(offset, ui::BACKWARDS_DIRECTION); - *end_offset = FindStartOfStyle(offset, ui::FORWARDS_DIRECTION); + *start_offset = + FindStartOfStyle(offset, ui::AXTextBoundaryDirection::kBackwards); + *end_offset = + FindStartOfStyle(offset, ui::AXTextBoundaryDirection::kForwards); base::string16 attributes_str; const std::vector<base::string16>& attributes = @@ -2110,7 +2114,7 @@ LONG BrowserAccessibilityComWin::FindIA2Boundary( IA2TextBoundaryType ia2_boundary, LONG start_offset, - ui::TextBoundaryDirection direction) { + ui::AXTextBoundaryDirection direction) { HandleSpecialTextOffset(&start_offset); // If the |start_offset| is equal to the location of the caret, then use the @@ -2128,13 +2132,13 @@ LONG BrowserAccessibilityComWin::FindStartOfStyle( LONG start_offset, - ui::TextBoundaryDirection direction) { + ui::AXTextBoundaryDirection direction) { LONG text_length = static_cast<LONG>(GetHypertext().length()); DCHECK_GE(start_offset, 0); DCHECK_LE(start_offset, text_length); switch (direction) { - case ui::BACKWARDS_DIRECTION: { + case ui::AXTextBoundaryDirection::kBackwards: { if (offset_to_text_attributes().empty()) return 0; @@ -2142,7 +2146,7 @@ --iterator; return static_cast<LONG>(iterator->first); } - case ui::FORWARDS_DIRECTION: { + case ui::AXTextBoundaryDirection::kForwards: { const auto iterator = offset_to_text_attributes().upper_bound(start_offset); if (iterator == offset_to_text_attributes().end())
diff --git a/content/browser/accessibility/browser_accessibility_com_win.h b/content/browser/accessibility/browser_accessibility_com_win.h index bf33f4c9..d6a2789 100644 --- a/content/browser/accessibility/browser_accessibility_com_win.h +++ b/content/browser/accessibility/browser_accessibility_com_win.h
@@ -39,7 +39,7 @@ namespace ui { -enum TextBoundaryDirection; +enum class AXTextBoundaryDirection; } // namespace ui @@ -472,12 +472,13 @@ // text boundary is found, and return the offset of that boundary. LONG FindIA2Boundary(IA2TextBoundaryType ia2_boundary, LONG start_offset, - ui::TextBoundaryDirection direction); + ui::AXTextBoundaryDirection direction); // Searches forward from the given offset until the start of the next style // is found, or searches backward from the given offset until the start of the // current style is found. - LONG FindStartOfStyle(LONG start_offset, ui::TextBoundaryDirection direction); + LONG FindStartOfStyle(LONG start_offset, + ui::AXTextBoundaryDirection direction); // ID refers to the node ID in the current tree, not the globally unique ID. // TODO(nektar): Could we use globally unique IDs everywhere?
diff --git a/content/browser/android/content_feature_list.cc b/content/browser/android/content_feature_list.cc index 4c31a3cf..ed536eb8 100644 --- a/content/browser/android/content_feature_list.cc +++ b/content/browser/android/content_feature_list.cc
@@ -39,8 +39,6 @@ } // namespace // Alphabetical: -const base::Feature kRequestUnbufferedDispatch{ - "RequestUnbufferedDispatch", base::FEATURE_ENABLED_BY_DEFAULT}; const base::Feature kServiceGroupImportance{"ServiceGroupImportance", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/browser/android/content_feature_list.h b/content/browser/android/content_feature_list.h index 41333477..6c2ccd2 100644 --- a/content/browser/android/content_feature_list.h +++ b/content/browser/android/content_feature_list.h
@@ -11,7 +11,6 @@ namespace android { // Alphabetical: -extern const base::Feature kRequestUnbufferedDispatch; extern const base::Feature kServiceGroupImportance; } // namespace android
diff --git a/content/browser/back_forward_cache_browsertest.cc b/content/browser/back_forward_cache_browsertest.cc index c347ed5d..347a9ef 100644 --- a/content/browser/back_forward_cache_browsertest.cc +++ b/content/browser/back_forward_cache_browsertest.cc
@@ -9,6 +9,7 @@ #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/site_isolation_policy.h" #include "content/public/common/content_features.h" +#include "content/public/common/content_switches.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" @@ -34,11 +35,15 @@ class BackForwardCacheBrowserTest : public ContentBrowserTest { protected: void SetUpCommandLine(base::CommandLine* command_line) override { + base::CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kUseFakeUIForMediaStream); feature_list_.InitAndEnableFeature(features::kBackForwardCache); + ContentBrowserTest::SetUpCommandLine(command_line); } void SetUpOnMainThread() override { host_resolver()->AddRule("*", "127.0.0.1"); + ContentBrowserTest::SetUpOnMainThread(); } WebContentsImpl* web_contents() const { @@ -719,6 +724,33 @@ } IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, + DoesNotCacheIfRecordingAudio) { + ASSERT_TRUE(embedded_test_server()->Start()); + + // Navigate to an empty page. + GURL url(embedded_test_server()->GetURL("/title1.html")); + EXPECT_TRUE(NavigateToURL(shell(), url)); + + // Request for audio recording. + EXPECT_EQ("success", EvalJs(current_frame_host(), R"( + new Promise(resolve => { + navigator.mediaDevices.getUserMedia({audio: true}) + .then(m => { resolve("success"); }) + .catch(() => { resolve("error"); }); + }); + )")); + + RenderFrameDeletedObserver deleted(current_frame_host()); + + // 2) Navigate away. + shell()->LoadURL(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // The page was still recording audio when we navigated away, so it shouldn't + // have been cached. + deleted.WaitUntilDeleted(); +} + +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, DoesNotCacheIfMainFrameStillLoading) { net::test_server::ControllableHttpResponse response(embedded_test_server(), "/main_document"); @@ -997,4 +1029,51 @@ delete_observer_rfh_a.WaitUntilDeleted(); } +// Tests the events are fired when going back from the cache. +IN_PROC_BROWSER_TEST_F(BackForwardCacheBrowserTest, Events) { + ASSERT_TRUE(embedded_test_server()->Start()); + GURL url_a(embedded_test_server()->GetURL("a.com", "/title1.html")); + GURL url_b(embedded_test_server()->GetURL("b.com", "/title1.html")); + + // 1) Navigate to A. + EXPECT_TRUE(NavigateToURL(shell(), url_a)); + RenderFrameHostImpl* rfh_a = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_a(rfh_a); + EXPECT_TRUE(ExecJs(shell(), R"( + window.testObservedEvents = []; + let event_list = [ + 'visibilitychange', + 'pagehide', + 'pageshow', + 'freeze', + 'resume', + ]; + for (event of event_list) { + let event2 = event; + document.addEventListener(event, + () => window.testObservedEvents.push(event2)); + } + )")); + + // 2) Navigate to B. + EXPECT_TRUE(NavigateToURL(shell(), url_b)); + RenderFrameHostImpl* rfh_b = current_frame_host(); + RenderFrameDeletedObserver delete_observer_rfh_b(rfh_b); + + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_FALSE(delete_observer_rfh_b.deleted()); + EXPECT_TRUE(rfh_a->is_in_back_forward_cache()); + EXPECT_FALSE(rfh_b->is_in_back_forward_cache()); + + // 3) Go back to A. Confirm that expected events are fired. + web_contents()->GetController().GoBack(); + EXPECT_TRUE(WaitForLoadStop(shell()->web_contents())); + EXPECT_FALSE(delete_observer_rfh_a.deleted()); + EXPECT_FALSE(delete_observer_rfh_b.deleted()); + EXPECT_EQ(rfh_a, current_frame_host()); + EXPECT_EQ( + ListValueOf("visibilitychange", "freeze", "resume", "visibilitychange"), + EvalJs(shell(), "window.testObservedEvents")); +} + } // namespace content
diff --git a/content/browser/frame_host/back_forward_cache.cc b/content/browser/frame_host/back_forward_cache.cc index 86620b0..f69e1cc 100644 --- a/content/browser/frame_host/back_forward_cache.cc +++ b/content/browser/frame_host/back_forward_cache.cc
@@ -7,6 +7,7 @@ #include <unordered_set> #include "content/browser/frame_host/frame_tree_node.h" +#include "content/browser/frame_host/render_frame_host_delegate.h" #include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/page_messages.h" @@ -97,6 +98,14 @@ if (!IsBackForwardCacheEnabled() || is_disabled_for_testing_) return false; + // If the rfh has ever granted media access, prevent it from entering cache. + // TODO(crbug.com/989379): Consider only blocking when there's an active + // media stream. + // TODO(crbug.com/989379): Consider also checking whether any subframes + // have requested an media stream. + if (rfh->was_granted_media_access()) + return false; + // Note that we check is_loading on the rfh directly, rather than calling // FrameTreeNode::IsLoading. This is because FrameTreeNode is already // loading the new page being navigated to.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index 34bdc77..b51039b 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1096,6 +1096,10 @@ child->current_frame_host()->LeaveBackForwardCache(); } +void RenderFrameHostImpl::OnGrantedMediaStreamAccess() { + was_granted_media_access_ = true; +} + void RenderFrameHostImpl::OnPortalActivated( const base::UnguessableToken& portal_token, mojo::PendingAssociatedRemote<blink::mojom::Portal> portal,
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index 44f3446..63ca195 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -902,6 +902,11 @@ void LeaveBackForwardCache(); // The document leaves the BackForwardCache. bool is_in_back_forward_cache() { return is_in_back_forward_cache_; } + // Called to taint |this| so the pages which have requested MediaStream + // (audio/video/etc capture stream) access would not enter BackForwardCache. + void OnGrantedMediaStreamAccess(); + bool was_granted_media_access() { return was_granted_media_access_; } + // Request a new NavigationClient interface from the renderer and returns the // ownership of the AssociatedPtr. This is intended for use by the // NavigationRequest. Only used with PerNavigationMojoInterface enabled. @@ -2306,6 +2311,9 @@ // this file. std::unique_ptr<BundledExchangesHandle> bundled_exchanges_handle_; + // Tainted once MediaStream access was granted. + bool was_granted_media_access_ = false; + // NOTE: This must be the last member. base::WeakPtrFactory<RenderFrameHostImpl> weak_ptr_factory_{this};
diff --git a/content/browser/frame_host/render_frame_message_filter_browsertest.cc b/content/browser/frame_host/render_frame_message_filter_browsertest.cc index 318f9b81..5cf74934 100644 --- a/content/browser/frame_host/render_frame_message_filter_browsertest.cc +++ b/content/browser/frame_host/render_frame_message_filter_browsertest.cc
@@ -302,18 +302,20 @@ void SetCookieFromString(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const std::string& cookie, SetCookieFromStringCallback callback) override { GetForwardingInterface()->SetCookieFromString( - URLToUse(url), std::move(site_for_cookies), std::move(cookie), + URLToUse(url), site_for_cookies, top_frame_origin, std::move(cookie), std::move(callback)); } void GetCookiesString(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, GetCookiesStringCallback callback) override { GetForwardingInterface()->GetCookiesString( - URLToUse(url), std::move(site_for_cookies), std::move(callback)); + URLToUse(url), site_for_cookies, top_frame_origin, std::move(callback)); } private:
diff --git a/content/browser/media/android/media_resource_getter_impl.cc b/content/browser/media/android/media_resource_getter_impl.cc index 100a9eca..aae91f3 100644 --- a/content/browser/media/android/media_resource_getter_impl.cc +++ b/content/browser/media/android/media_resource_getter_impl.cc
@@ -23,6 +23,7 @@ #include "net/http/http_auth.h" #include "services/network/public/mojom/restricted_cookie_manager.mojom.h" #include "url/gurl.h" +#include "url/origin.h" namespace content { @@ -148,8 +149,11 @@ browser_context_, url, render_process_id_, render_frame_id_); network::mojom::RestrictedCookieManager* cookie_manager_ptr = cookie_manager.get(); + // TODO(crbug.com/988398): Same check as in mojo_renderer_service.cc. Is this + // correct? + DCHECK(!site_for_cookies.is_empty()); cookie_manager_ptr->GetCookiesString( - url, site_for_cookies, + url, site_for_cookies, url::Origin::Create(site_for_cookies), base::BindOnce(&ReturnResultOnUIThreadAndClosePipe, std::move(cookie_manager), std::move(callback))); }
diff --git a/content/browser/renderer_host/media/media_stream_ui_proxy.cc b/content/browser/renderer_host/media/media_stream_ui_proxy.cc index 223b9e4..a5d08e2 100644 --- a/content/browser/renderer_host/media/media_stream_ui_proxy.cc +++ b/content/browser/renderer_host/media/media_stream_ui_proxy.cc
@@ -157,8 +157,7 @@ DCHECK_CURRENTLY_ON(BrowserThread::UI); blink::MediaStreamDevices filtered_devices; - RenderFrameHost* host = - RenderFrameHost::FromID(render_process_id, render_frame_id); + auto* host = RenderFrameHostImpl::FromID(render_process_id, render_frame_id); for (const blink::MediaStreamDevice& device : devices) { if (device.type == blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE && !IsFeatureEnabled(host, tests_use_fake_render_frame_hosts_, @@ -181,6 +180,9 @@ if (stream_ui) ui_ = std::move(stream_ui); + if (host && result == blink::mojom::MediaStreamRequestResult::OK) + host->OnGrantedMediaStreamAccess(); + base::PostTask( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&MediaStreamUIProxy::ProcessAccessRequestResponse, proxy_,
diff --git a/content/browser/service_worker/service_worker_registration_unittest.cc b/content/browser/service_worker/service_worker_registration_unittest.cc index e3d58447..64490760 100644 --- a/content/browser/service_worker/service_worker_registration_unittest.cc +++ b/content/browser/service_worker/service_worker_registration_unittest.cc
@@ -173,7 +173,8 @@ class ServiceWorkerRegistrationTest : public testing::Test { public: ServiceWorkerRegistrationTest() - : thread_bundle_(TestBrowserThreadBundle::IO_MAINLOOP) {} + : thread_bundle_(base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME, + TestBrowserThreadBundle::IO_MAINLOOP) {} void SetUp() override { helper_ = std::make_unique<EmbeddedWorkerTestHelper>(base::FilePath()); @@ -570,8 +571,6 @@ scoped_refptr<ServiceWorkerRegistration> reg = registration(); scoped_refptr<ServiceWorkerVersion> version_1 = reg->active_version(); scoped_refptr<ServiceWorkerVersion> version_2 = reg->waiting_version(); - auto runner = base::MakeRefCounted<base::TestSimpleTaskRunner>(); - reg->SetTaskRunnerForTest(runner); // Remove the controllee. Since there is an in-flight request, // activation should not yet happen. @@ -588,7 +587,9 @@ RequestTermination(&version_1_client()->host()); TestServiceWorkerObserver observer(helper_->context_wrapper()); - observer.RunUntilActivated(version_2.get(), runner); + observer.RunUntilStatusChange(version_2.get(), + ServiceWorkerVersion::ACTIVATED); + EXPECT_EQ(ServiceWorkerVersion::ACTIVATED, version_2->status()); EXPECT_EQ(version_2.get(), reg->active_version()); }
diff --git a/content/browser/web_contents/web_contents_view_android.cc b/content/browser/web_contents/web_contents_view_android.cc index fef8779..10086ffc 100644 --- a/content/browser/web_contents/web_contents_view_android.cc +++ b/content/browser/web_contents/web_contents_view_android.cc
@@ -25,6 +25,7 @@ #include "content/public/browser/android/synchronous_compositor.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents_delegate.h" +#include "content/public/common/content_features.h" #include "content/public/common/drop_data.h" #include "ui/android/overscroll_refresh_handler.h" #include "ui/base/clipboard/clipboard.h" @@ -51,8 +52,7 @@ // compositor event queue. bool ShouldRequestUnbufferedDispatch() { static bool should_request_unbuffered_dispatch = - base::FeatureList::IsEnabled( - content::android::kRequestUnbufferedDispatch) && + base::FeatureList::IsEnabled(features::kRequestUnbufferedDispatch) && base::android::BuildInfo::GetInstance()->sdk_int() >= base::android::SDK_VERSION_LOLLIPOP && !content::GetContentClient()->UsingSynchronousCompositing();
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 567de30..b009e83 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -235,11 +235,6 @@ WebRuntimeFeatures::EnableScrollAnchorSerialization(true); WebRuntimeFeatures::EnableFeatureFromString( - "BlinkGenPropertyTrees", - base::FeatureList::IsEnabled(blink::features::kBlinkGenPropertyTrees) || - enable_experimental_web_platform_features); - - WebRuntimeFeatures::EnableFeatureFromString( "CSSBackdropFilter", base::FeatureList::IsEnabled(blink::features::kCSSBackdropFilter) || enable_experimental_web_platform_features);
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index d08f30f..308f919 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -435,6 +435,9 @@ const base::Feature kRenderingPipelineThrottling{ "RenderingPipelineThrottling", base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kRequestUnbufferedDispatch{ + "RequestUnbufferedDispatch", base::FEATURE_ENABLED_BY_DEFAULT}; + // Enables resampling input events on main thread. const base::Feature kResamplingInputEvents{"ResamplingInputEvents", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index f05012c..e43bde1 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -97,6 +97,7 @@ CONTENT_EXPORT extern const base::Feature kRenderDocumentForMainFrame; CONTENT_EXPORT extern const base::Feature kRenderDocumentForSubframe; CONTENT_EXPORT extern const base::Feature kRenderingPipelineThrottling; +CONTENT_EXPORT extern const base::Feature kRequestUnbufferedDispatch; CONTENT_EXPORT extern const base::Feature kResamplingInputEvents; CONTENT_EXPORT extern const base::Feature kResourceLoadScheduler; CONTENT_EXPORT extern const base::Feature
diff --git a/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc b/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc index dc21c32b..461fc91 100644 --- a/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc +++ b/content/shell/browser/web_test/web_test_bluetooth_adapter_provider.cc
@@ -343,7 +343,7 @@ // Any unexpected call results in the failure callback. ON_CALL(*adapter, StartScanWithFilter_(_, _)) .WillByDefault(RunCallbackWithResult<1 /* result_callback */>( - true /*is_error*/, + /*is_error=*/true, device::UMABluetoothDiscoverySessionOutcome::UNKNOWN)); // We need to add a device otherwise requestDevice would reject. @@ -359,7 +359,7 @@ ON_CALL(*adapter, StartScanWithFilter_(_, _)) .WillByDefault(RunCallbackWithResult<1 /* result_callback */>( - true /*is_error*/, + /*is_error=*/true, device::UMABluetoothDiscoverySessionOutcome::UNKNOWN)); return adapter; @@ -374,7 +374,7 @@ ON_CALL(*adapter, StartScanWithFilter_(_, _)) .WillByDefault(RunCallbackWithResultFunction<1 /* result_callback */>( - false /*is_error*/, [adapter_ptr]() { + /*is_error=*/false, [adapter_ptr]() { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&NotifyDevicesAdded, base::RetainedRef(adapter_ptr))); @@ -382,6 +382,15 @@ return device::UMABluetoothDiscoverySessionOutcome::SUCCESS; })); + ON_CALL(*adapter, StopScan(_)) + .WillByDefault( + Invoke([](device::BluetoothAdapter::DiscoverySessionResultCallback + callback) { + std::move(callback).Run( + /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + })); + return adapter; } @@ -421,10 +430,10 @@ EXPECT_CALL(*adapter, StartScanWithFilter_(_, _)) .WillOnce(RunCallbackWithResult<1 /* result_callback */>( - false /*is_error*/, + /*is_error=*/false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS)) .WillOnce(RunCallbackWithResultFunction<1 /* result_callback */>( - false /*is_error*/, [adapter_ptr]() { + /*is_error=*/false, [adapter_ptr]() { // In the second discovery session, have the adapter discover a new // device, shortly after the session starts. base::ThreadTaskRunnerHandle::Get()->PostTask( @@ -434,6 +443,17 @@ return device::UMABluetoothDiscoverySessionOutcome::SUCCESS; })); + EXPECT_CALL(*adapter, StopScan(_)).Times(2); + + ON_CALL(*adapter, StopScan(_)) + .WillByDefault( + Invoke([](device::BluetoothAdapter::DiscoverySessionResultCallback + callback) { + std::move(callback).Run( + /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + })); + return adapter; } @@ -478,7 +498,7 @@ ON_CALL(*adapter, StartScanWithFilter_(_, _)) .WillByDefault(RunCallbackWithResultFunction<1 /* result_callback */>( - false /*is_error*/, + /*is_error=*/false, [adapter_ptr, changing_battery_ptr, discovery_generic_access_ptr]() { if (adapter_ptr->GetDevices().size() == 4) { // Post task to add NewGlucoseDevice. @@ -509,6 +529,15 @@ return device::UMABluetoothDiscoverySessionOutcome::SUCCESS; })); + ON_CALL(*adapter, StopScan(_)) + .WillByDefault( + Invoke([](device::BluetoothAdapter::DiscoverySessionResultCallback + callback) { + std::move(callback).Run( + /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + })); + return adapter; } @@ -528,7 +557,7 @@ ON_CALL(*adapter, StartScanWithFilter_(_, _)) .WillByDefault(RunCallbackWithResultFunction<1 /* result_callback */>( - false /*is_error*/, [adapter_ptr, connected_hr_address]() { + /*is_error=*/false, [adapter_ptr, connected_hr_address]() { if (adapter_ptr->GetDevices().size() == 1) { // Post task to add NewGlucoseDevice. auto glucose_device(GetBaseDevice(
diff --git a/content/shell/browser/web_test/web_test_devtools_bindings.cc b/content/shell/browser/web_test/web_test_devtools_bindings.cc index 740b00b4..489682b 100644 --- a/content/shell/browser/web_test/web_test_devtools_bindings.cc +++ b/content/shell/browser/web_test/web_test_devtools_bindings.cc
@@ -88,19 +88,19 @@ base::FilePath dev_tools_path; bool is_debug_dev_tools = base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDebugDevTools); + std::string url_string; if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kCustomDevToolsFrontend)) { - dev_tools_path = base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( + url_string = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( switches::kCustomDevToolsFrontend); } else { - std::string folder = is_debug_dev_tools ? "debug/" : ""; - dev_tools_path = dir_exe.AppendASCII("resources/inspector/" + folder); + // The test runner hosts DevTools resources at this path by default. + url_string = "http://localhost:8000/inspector-sources/"; + if (is_debug_dev_tools) + url_string += "debug/"; } - GURL result = net::FilePathToFileURL( - dev_tools_path.AppendASCII("integration_test_runner.html")); - std::string url_string = - base::StringPrintf("%s?experiments=true", result.spec().c_str()); + url_string += "integration_test_runner.html?experiments=true"; if (is_debug_dev_tools) url_string += "&debugFrontend=true"; url_string += "&test=" + test_url_string;
diff --git a/content/test/data/browsing_data/site_data.html b/content/test/data/browsing_data/site_data.html index 5e798c828..0a2a8883 100644 --- a/content/test/data/browsing_data/site_data.html +++ b/content/test/data/browsing_data/site_data.html
@@ -74,7 +74,7 @@ function openFile_(name, options, callback, error) { window.webkitRequestFileSystem(TEMPORARY, 1024, function (fs) { fs.root.getFile(name, options, callback, error); - }); + }, error); } function setFileSystem() { @@ -113,6 +113,7 @@ open.result.close(); success_(); } + open.onerror = failure_; } function hasIndexedDb() { @@ -122,6 +123,7 @@ open.result.close(); domAutomationController.send(hasStore); } + open.onerror = failure_; } function setHistory() {
diff --git a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt index 3d1a981..d45f5fc2 100644 --- a/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/pixel_expectations.txt
@@ -59,6 +59,8 @@ crbug.com/805739 [ android-webview-instrumentation ] Pixel_OffscreenCanvasWebGLPaintAfterResize [ Skip ] crbug.com/805739 [ android-webview-instrumentation ] Pixel_OffscreenCanvasWebglResizeOnWorker [ Skip ] crbug.com/805739 [ android android-webview-instrumentation ] Pixel_CanvasLowLatencyWebGL [ Skip ] +crbug.com/992599 [ android android-webview-instrumentation ] Pixel_OffscreenCanvasTransferToImageBitmapWorker [ Skip ] +crbug.com/992599 [ android android-webview-instrumentation ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ] # Fails on Android WebView due to requiring embedding viz clients. crbug.com/805739 # Produces black images on Nexus 5Xs in Android Webview (qualcomm-adreno-(tm)-418) crbug.com/984352 @@ -204,8 +206,8 @@ crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasAccelerated2DWorker [ Skip ] crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferAfterStyleResize [ Skip ] crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferBeforeStyleResize [ Skip ] -crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ] -crbug.com/969864 [ android skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferToImageBitmapWorker [ Skip ] +crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferToImageBitmap [ Skip ] +crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasTransferToImageBitmapWorker [ Skip ] crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLDefault [ Skip ] crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebGLDefaultWorker [ Skip ] crbug.com/969864 [ android android-chromium skia-renderer use-vulkan ] Pixel_OffscreenCanvasWebglResizeOnWorker [ Skip ]
diff --git a/device/bluetooth/bluetooth_adapter.cc b/device/bluetooth/bluetooth_adapter.cc index efe6f9b4..6497230 100644 --- a/device/bluetooth/bluetooth_adapter.cc +++ b/device/bluetooth/bluetooth_adapter.cc
@@ -9,6 +9,8 @@ #include <utility> #include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/memory/ptr_util.h" #include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" #include "build/build_config.h" @@ -108,27 +110,81 @@ std::unique_ptr<BluetoothDiscoverySession> new_session( new BluetoothDiscoverySession(this, std::move(discovery_filter))); discovery_sessions_.insert(new_session.get()); - auto result_callback = - base::BindOnce(&BluetoothAdapter::OnStartDiscoverySessionCallback, - weak_ptr_factory_.GetWeakPtr(), std::move(new_session), - callback, error_callback); - auto current_filter = GetMergedDiscoveryFilter(); - if (discovery_sessions_.size() > 1) { - UpdateFilter(std::move(current_filter), std::move(result_callback)); - } else { - StartScanWithFilter(std::move(current_filter), std::move(result_callback)); + + auto new_session_callbacks = + base::WrapUnique(new StartOrStopDiscoveryCallback( + base::BindOnce(callback, std::move(new_session)), error_callback)); + + // Queue up the callbacks to be handled when we process the discovery queue. + discovery_callback_queue_.push(std::move(new_session_callbacks)); + + // If OS is already working on a discovery request we must wait to process the + // queue until that request is complete. + if (discovery_request_pending_) { + return; } + + // The OS is ready to start a request so process the queue now. + ProcessDiscoveryQueue(); +} + +void BluetoothAdapter::MaybeUpdateFilter( + std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, + DiscoverySessionResultCallback callback) { + if (discovery_filter->Equals(current_discovery_filter_)) { + std::move(callback).Run(/*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::SUCCESS); + return; + } + + UpdateFilter(std::move(discovery_filter), std::move(callback)); +} + +void BluetoothAdapter::RemoveDiscoverySession( + BluetoothDiscoverySession* discovery_session, + const base::Closure& callback, + DiscoverySessionErrorCallback error_callback) { + size_t erased = discovery_sessions_.erase(discovery_session); + DCHECK_EQ(1u, erased); + + std::unique_ptr<StartOrStopDiscoveryCallback> removal_callbacks( + new StartOrStopDiscoveryCallback(callback, std::move(error_callback))); + + // Queue up the callbacks to be handled when we process the discovery queue. + discovery_callback_queue_.push(std::move(removal_callbacks)); + + // If OS is already working on a discovery request we must wait to process the + // queue until that request is complete. + if (discovery_request_pending_) { + return; + } + + // The OS is ready to start a request so process the queue now. + ProcessDiscoveryQueue(); } std::unique_ptr<BluetoothDiscoveryFilter> BluetoothAdapter::GetMergedDiscoveryFilter() const { - return GetMergedDiscoveryFilterHelper(nullptr, false); -} + auto result = + std::make_unique<BluetoothDiscoveryFilter>(BLUETOOTH_TRANSPORT_DUAL); + bool first_merge = true; -std::unique_ptr<BluetoothDiscoveryFilter> -BluetoothAdapter::GetMergedDiscoveryFilterMasked( - BluetoothDiscoveryFilter* masked_filter) const { - return GetMergedDiscoveryFilterHelper(masked_filter, true); + for (auto* iter : discovery_sessions_) { + if (!iter->IsActive()) + continue; + + const BluetoothDiscoveryFilter* curr_filter = iter->GetDiscoveryFilter(); + + if (first_merge) { + first_merge = false; + if (curr_filter) { + result->CopyFrom(*curr_filter); + } + continue; + } + result = BluetoothDiscoveryFilter::Merge(result.get(), curr_filter); + } + return result; } BluetoothAdapter::DeviceList BluetoothAdapter::GetDevices() { @@ -346,13 +402,27 @@ BluetoothAdapter::SetPoweredCallbacks::SetPoweredCallbacks() = default; BluetoothAdapter::SetPoweredCallbacks::~SetPoweredCallbacks() = default; -BluetoothAdapter::BluetoothAdapter() {} +BluetoothAdapter::StartOrStopDiscoveryCallback::StartOrStopDiscoveryCallback( + base::OnceClosure start_callback, + ErrorCallback start_error_callback) { + this->start_callback = std::move(start_callback); + this->start_error_callback = start_error_callback; +} +BluetoothAdapter::StartOrStopDiscoveryCallback::StartOrStopDiscoveryCallback( + base::Closure stop_callback, + DiscoverySessionErrorCallback stop_error_callback) { + this->stop_callback = stop_callback; + this->stop_error_callback = std::move(stop_error_callback); +} +BluetoothAdapter::StartOrStopDiscoveryCallback:: + ~StartOrStopDiscoveryCallback() = default; + +BluetoothAdapter::BluetoothAdapter() : weak_ptr_factory_(this) {} BluetoothAdapter::~BluetoothAdapter() { // If there's a pending powered request, run its error callback. - if (set_powered_callbacks_) { + if (set_powered_callbacks_) set_powered_callbacks_->error_callback.Run(); - } } void BluetoothAdapter::RunPendingPowerCallbacks() { @@ -366,40 +436,105 @@ } } -void BluetoothAdapter::OnStartDiscoverySessionCallback( - std::unique_ptr<BluetoothDiscoverySession> discovery_session, - const DiscoverySessionCallback& callback, - const ErrorCallback& error_callback, +void BluetoothAdapter::OnDiscoveryChangeComplete( bool is_error, UMABluetoothDiscoverySessionOutcome outcome) { + UpdateDiscoveryState(is_error); + if (is_error) { - OnStartDiscoverySessionError(std::move(discovery_session), error_callback, - outcome); - } else { - OnStartDiscoverySession(std::move(discovery_session), callback); + NotifyDiscoveryError(std::move(callbacks_awaiting_response_)); + discovery_request_pending_ = false; + ProcessDiscoveryQueue(); + return; + } + + current_discovery_filter_.CopyFrom(filter_being_set_); + + while (!callbacks_awaiting_response_.empty()) { + std::unique_ptr<StartOrStopDiscoveryCallback> callbacks = + std::move(callbacks_awaiting_response_.front()); + callbacks_awaiting_response_.pop(); + if (callbacks->start_callback) + std::move(callbacks->start_callback).Run(); + + if (callbacks->stop_callback) + std::move(callbacks->stop_callback).Run(); + } + discovery_request_pending_ = false; + ProcessDiscoveryQueue(); +} + +void BluetoothAdapter::UpdateDiscoveryState(bool is_error) { + if (is_error) { + if (internal_discovery_state_ == DiscoveryState::kStarting) + internal_discovery_state_ = DiscoveryState::kIdle; + // If there was an error stopping we still assume it worked as there is not + // much we can do about the device messing up. + if (internal_discovery_state_ == DiscoveryState::kStopping) + internal_discovery_state_ = DiscoveryState::kIdle; + return; + } + + if (internal_discovery_state_ == DiscoveryState::kStarting) + internal_discovery_state_ = DiscoveryState::kDiscovering; + if (internal_discovery_state_ == DiscoveryState::kStopping) + internal_discovery_state_ = DiscoveryState::kIdle; +} + +void BluetoothAdapter::ProcessDiscoveryQueue() { + if (discovery_callback_queue_.empty()) + return; + DCHECK(callbacks_awaiting_response_.empty()); + callbacks_awaiting_response_.swap(discovery_callback_queue_); + + if (NumDiscoverySessions() == 0) { + if (internal_discovery_state_ == DiscoveryState::kIdle) { + OnDiscoveryChangeComplete(false, + UMABluetoothDiscoverySessionOutcome::SUCCESS); + return; + } + internal_discovery_state_ = DiscoveryState::kStopping; + discovery_request_pending_ = true; + StopScan(base::BindOnce(&BluetoothAdapter::OnDiscoveryChangeComplete, + weak_ptr_factory_.GetWeakPtr())); + + return; + } + + auto result_callback = + base::BindOnce(&BluetoothAdapter::OnDiscoveryChangeComplete, + weak_ptr_factory_.GetWeakPtr()); + auto new_desired_filter = GetMergedDiscoveryFilter(); + discovery_request_pending_ = true; + filter_being_set_.CopyFrom(*new_desired_filter.get()); + if (internal_discovery_state_ == DiscoveryState::kDiscovering) { + MaybeUpdateFilter(std::move(new_desired_filter), + std::move(result_callback)); + return; + } + internal_discovery_state_ = DiscoveryState::kStarting; + StartScanWithFilter(std::move(new_desired_filter), + std::move(result_callback)); +} + +void BluetoothAdapter::NotifyDiscoveryError(CallbackQueue callback_queue) { + while (!callback_queue.empty()) { + std::unique_ptr<StartOrStopDiscoveryCallback> callbacks = + std::move(callback_queue.front()); + callback_queue.pop(); + if (callbacks->start_error_callback) + callbacks->start_error_callback.Run(); + // We never return error when stopping. If the physical adapter is messing + // up and not stopping we are still just going to continue like it did stop. + if (callbacks->stop_callback) + std::move(callbacks->stop_callback).Run(); } } -void BluetoothAdapter::OnStartDiscoverySession( - std::unique_ptr<BluetoothDiscoverySession> discovery_session, - const DiscoverySessionCallback& callback) { - VLOG(1) << "BluetoothAdapter::OnStartDiscoverySession"; - RecordBluetoothDiscoverySessionStartOutcome( - UMABluetoothDiscoverySessionOutcome::SUCCESS); - callback.Run(std::move(discovery_session)); -} - -void BluetoothAdapter::OnStartDiscoverySessionError( - std::unique_ptr<BluetoothDiscoverySession> discovery_session, - const ErrorCallback& callback, - UMABluetoothDiscoverySessionOutcome outcome) { - VLOG(1) << "OnStartDiscoverySessionError: " << static_cast<int>(outcome); - discovery_session->MarkAsInactive(); - RecordBluetoothDiscoverySessionStartOutcome(outcome); - callback.Run(); -} - void BluetoothAdapter::MarkDiscoverySessionsAsInactive() { + // All sessions are becoming inactive so any pending requests should now fail + if (!discovery_callback_queue_.empty()) + NotifyDiscoveryError(std::move(discovery_callback_queue_)); // As sessions are marked as inactive they will notify the adapter that they // have become inactive, upon which the adapter will remove them from // |discovery_sessions_|. To avoid invalidating the iterator, make a copy @@ -407,55 +542,14 @@ std::set<BluetoothDiscoverySession*> temp(discovery_sessions_); for (auto iter = temp.begin(); iter != temp.end(); ++iter) { (*iter)->MarkAsInactive(); + RemoveDiscoverySession(*iter, base::DoNothing(), base::DoNothing()); } } -void BluetoothAdapter::DiscoverySessionBecameInactive( - BluetoothDiscoverySession* discovery_session) { - DCHECK(!discovery_session->IsActive()); - size_t erased = discovery_sessions_.erase(discovery_session); - DCHECK_EQ(1u, erased); -} - void BluetoothAdapter::DeleteDeviceForTesting(const std::string& address) { devices_.erase(address); } -std::unique_ptr<BluetoothDiscoveryFilter> -BluetoothAdapter::GetMergedDiscoveryFilterHelper( - const BluetoothDiscoveryFilter* masked_filter, - bool omit) const { - std::unique_ptr<BluetoothDiscoveryFilter> result; - bool first_merge = true; - - std::set<BluetoothDiscoverySession*> temp(discovery_sessions_); - for (auto* iter : temp) { - const BluetoothDiscoveryFilter* curr_filter = iter->GetDiscoveryFilter(); - - if (!iter->IsActive()) - continue; - - if (omit && curr_filter == masked_filter) { - // if masked_filter is pointing to empty filter, and there are - // multiple empty filters in discovery_sessions_, make sure we'll - // process next empty sessions. - omit = false; - continue; - } - - if (first_merge) { - first_merge = false; - if (curr_filter) { - result.reset(new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_DUAL)); - result->CopyFrom(*curr_filter); - } - continue; - } - result = BluetoothDiscoveryFilter::Merge(result.get(), curr_filter); - } - return result; -} - void BluetoothAdapter::RemoveTimedOutDevices() { for (auto it = devices_.begin(); it != devices_.end();) { BluetoothDevice* device = it->second.get();
diff --git a/device/bluetooth/bluetooth_adapter.h b/device/bluetooth/bluetooth_adapter.h index 0e24b27c..92546bb0 100644 --- a/device/bluetooth/bluetooth_adapter.h +++ b/device/bluetooth/bluetooth_adapter.h
@@ -16,12 +16,14 @@ #include <vector> #include "base/callback.h" +#include "base/containers/queue.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "build/build_config.h" #include "device/bluetooth/bluetooth_advertisement.h" #include "device/bluetooth/bluetooth_device.h" +#include "device/bluetooth/bluetooth_discovery_filter.h" #include "device/bluetooth/bluetooth_export.h" namespace base { @@ -342,6 +344,13 @@ base::OnceCallback<void(/*is_error*/ bool, UMABluetoothDiscoverySessionOutcome)>; + enum class DiscoveryState { + kStarting = 0, + kStopping, + kDiscovering, + kIdle, + }; + // Returns a weak pointer to a new adapter. For platforms with asynchronous // initialization, the returned adapter will run the |init_callback| once // asynchronous initialization is complete. @@ -468,12 +477,6 @@ // Return all discovery filters assigned to this adapter merged together. std::unique_ptr<BluetoothDiscoveryFilter> GetMergedDiscoveryFilter() const; - // Works like GetMergedDiscoveryFilter, but doesn't take |masked_filter| into - // account. |masked_filter| is compared by pointer, and must be a member of - // active session. - std::unique_ptr<BluetoothDiscoveryFilter> GetMergedDiscoveryFilterMasked( - BluetoothDiscoveryFilter* masked_filter) const; - // Requests the list of devices from the adapter. All devices are returned, // including those currently connected, those paired and all devices returned // by RetrieveGattConnectedDevicesWithDiscoveryFilter() (from the previous @@ -616,6 +619,28 @@ // The timeout in seconds used by RemoveTimedOutDevices. static const base::TimeDelta timeoutSec; + // This struct is meant to hold any possible callback from a discovery + // request. The purpose of this is to consolidate all discovery request + // callbacks into one array that can be handled all at once when the state + // desired from all requests is achieved or an error is thrown. + struct StartOrStopDiscoveryCallback { + StartOrStopDiscoveryCallback(base::OnceClosure start_callback, + ErrorCallback start_error_callback); + StartOrStopDiscoveryCallback( + base::Closure stop_callback, + DiscoverySessionErrorCallback stop_error_callback); + ~StartOrStopDiscoveryCallback(); + + // The success callback for a start discovery request + base::OnceClosure start_callback; + // The success callback for a stop discovery request + base::Closure stop_callback; + // The error callback for a start discovery request + ErrorCallback start_error_callback; + // The error callback for a stop discovery request + DiscoverySessionErrorCallback stop_error_callback; + }; + protected: friend class base::RefCounted<BluetoothAdapter>; friend class BluetoothDiscoverySession; @@ -626,6 +651,9 @@ using PairingDelegatePair = std::pair<BluetoothDevice::PairingDelegate*, PairingDelegatePriority>; + using CallbackQueue = + base::queue<std::unique_ptr<StartOrStopDiscoveryCallback>>; + // Implementations on Android and macOS need to store pending SetPowered() // callbacks until an appropriate event is received, due to a lack of blocking // or callback supporting platform APIs. Declaring the struct here allows @@ -670,40 +698,31 @@ // - When finished it should call the callback with success or the // appropriate output for an error // - // On a call to RemoveDiscoverySession: - // - If there is a pending request to the subsystem, queue this request to - // execute once the pending requests are done. - // - If the count is 0, return failure, as there is no active discovery - // session. - // - If the count is 1, issue a request to the subsystem to stop device - // discovery and decrement the count to 0 on success. - // - If the count is greater than 1, decrement the count and return - // success. - // - // |discovery_filter| passed to AddDiscoverySession and RemoveDiscoverySession - // is owned by other objects and shall not be freed. When the count is - // greater than 0 and AddDiscoverySession or RemoveDiscoverySession is called - // the filter being used by the underlying controller must be updated. - // - // These methods invoke |callback| for success and |error_callback| for - // failures. + // On a call to StopScan: + // - Make a request to the physical adapter that we no longer needs to + // be scanning + // - When finished it should callback with success. If an error is thrown + // we still return success to the user and update our internal state to + // say that we are not discovering. + virtual void StartScanWithFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) = 0; virtual void UpdateFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) = 0; - virtual void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) = 0; + virtual void StopScan(DiscoverySessionResultCallback callback) = 0; - // Used to set and update the discovery filter used by the underlying - // Bluetooth controller. - virtual void SetDiscoveryFilter( + // Removes the |discovery_session| from |discovery_sessions_| and updates + // accordingly + void RemoveDiscoverySession(BluetoothDiscoverySession* discovery_session, + const base::Closure& callback, + DiscoverySessionErrorCallback error_callback); + // Helper function that short circuits a successful callback if the filter is + // the same as the current filter. + void MaybeUpdateFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) = 0; + DiscoverySessionResultCallback callback); // Called by RemovePairingDelegate() in order to perform any class-specific // internal functionality necessary to remove the pairing delegate, such as @@ -711,28 +730,11 @@ virtual void RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) = 0; - // Success callback passed to AddDiscoverySession by StartDiscoverySession. - void OnStartDiscoverySession( - std::unique_ptr<BluetoothDiscoverySession> discovery_session, - const DiscoverySessionCallback& callback); - - // Error callback passed to AddDiscoverySession by StartDiscoverySession. - void OnStartDiscoverySessionError( - std::unique_ptr<BluetoothDiscoverySession> discovery_session, - const ErrorCallback& callback, - UMABluetoothDiscoverySessionOutcome outcome); - // Marks all known DiscoverySession instances as inactive. Called by // BluetoothAdapter in the event that the adapter unexpectedly stops // discovering. This should be called by all platform implementations. void MarkDiscoverySessionsAsInactive(); - // Removes |discovery_session| from |discovery_sessions_|, if its in there. - // Called by DiscoverySession when an instance is destroyed or becomes - // inactive. - void DiscoverySessionBecameInactive( - BluetoothDiscoverySession* discovery_session); - void DeleteDeviceForTesting(const std::string& address); // Removes from |devices_| any previously paired, connected or seen @@ -778,22 +780,43 @@ static void RecordBluetoothDiscoverySessionStopOutcome( UMABluetoothDiscoverySessionOutcome outcome); - // An adapter between DiscoverySessionResultCallback and - // DiscoverySessionCallback that calls either OnStartDiscoverySession() or - // OnStartDiscoverySessionError() based on the outcome of starting - // |discovery_session|. - void OnStartDiscoverySessionCallback( - std::unique_ptr<BluetoothDiscoverySession> discovery_session, - const DiscoverySessionCallback& callback, - const ErrorCallback& error_callback, - bool is_error, - UMABluetoothDiscoverySessionOutcome outcome); + // This is the callback for all OS level calls to StartScanWithFilter, + // UpdateFilter, and StopScan. It updates the state accordingly, calls all + // appropriate callbacks, and calls ProcessDiscoveryQueue(). + void OnDiscoveryChangeComplete(bool is_error, + UMABluetoothDiscoverySessionOutcome outcome); - // Return all discovery filters assigned to this adapter merged together. - // If |omit| is true, |discovery_filter| will not be processed. - std::unique_ptr<BluetoothDiscoveryFilter> GetMergedDiscoveryFilterHelper( - const BluetoothDiscoveryFilter* discovery_filter, - bool omit) const; + // This method processes all queued requests that have been waiting for a + // process to finish. + void ProcessDiscoveryQueue(); + + // Utility method used to call all callbacks in the case of an error in a + // process + void NotifyDiscoveryError(CallbackQueue queue); + + // Utility function to update our internal state after a process has + // completed(example: kStarting -> kDiscovering) + void UpdateDiscoveryState(bool is_error); + + // List of callbacks for requests that have been queued up and are awaiting a + // process to finish before they can begin the request + CallbackQueue discovery_callback_queue_; + // List of callbacks whose requests are currently being processed by the OS + // level adapter + CallbackQueue callbacks_awaiting_response_; + + // Discovery filter currently being used by the adapter + device::BluetoothDiscoveryFilter current_discovery_filter_; + // Discovery filter that is about to be set in the OS level adapter. After + // the process that is implementing this feature is finished this will become + // the |current_discovery_filter_|. + device::BluetoothDiscoveryFilter filter_being_set_; + + // True, if there is a pending request to start or stop discovery. + bool discovery_request_pending_ = false; + + // enum used to track our internal discovery state. + DiscoveryState internal_discovery_state_ = DiscoveryState::kIdle; // Note: This should remain the last member so it'll be destroyed and // invalidate its weak pointers before any other members are destroyed.
diff --git a/device/bluetooth/bluetooth_adapter_android.cc b/device/bluetooth/bluetooth_adapter_android.cc index 45de091..2a57ed2 100644 --- a/device/bluetooth/bluetooth_adapter_android.cc +++ b/device/bluetooth/bluetooth_adapter_android.cc
@@ -357,45 +357,21 @@ } } -void BluetoothAdapterAndroid::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - bool session_removed = false; - if (NumDiscoverySessions() == 0) { - VLOG(1) << "RemoveDiscoverySession: No scan in progress."; - NOTREACHED(); - } else { - session_removed = true; - if (NumDiscoverySessions() == 1) { - VLOG(1) << "RemoveDiscoverySession: Now 0 sessions. Stopping scan."; - session_removed = Java_ChromeBluetoothAdapter_stopScan( - AttachCurrentThread(), j_adapter_); - for (const auto& device_id_object_pair : devices_) { - device_id_object_pair.second->ClearAdvertisementData(); - } - } else { - VLOG(1) << "RemoveDiscoverySession: Now " - << unsigned(NumDiscoverySessions()) << " sessions."; - } - } +void BluetoothAdapterAndroid::StopScan( + DiscoverySessionResultCallback callback) { + DCHECK(NumDiscoverySessions() == 0); - if (session_removed) { - callback.Run(); + VLOG(1) << "Stopping scan."; + if (Java_ChromeBluetoothAdapter_stopScan(AttachCurrentThread(), j_adapter_)) { + std::move(callback).Run(/*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::SUCCESS); } else { // TODO(scheib): Eventually wire the SCAN_FAILED result through to here. - std::move(error_callback).Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN); + std::move(callback).Run(/*is_error=*/true, + UMABluetoothDiscoverySessionOutcome::UNKNOWN); } -} - -void BluetoothAdapterAndroid::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - // TODO(scheib): Support filters crbug.com/490401 - NOTIMPLEMENTED(); - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED); + for (const auto& device_id_object_pair : devices_) + device_id_object_pair.second->ClearAdvertisementData(); } void BluetoothAdapterAndroid::RemovePairingDelegateInternal(
diff --git a/device/bluetooth/bluetooth_adapter_android.h b/device/bluetooth/bluetooth_adapter_android.h index 1bca795..d8a4193b 100644 --- a/device/bluetooth/bluetooth_adapter_android.h +++ b/device/bluetooth/bluetooth_adapter_android.h
@@ -118,14 +118,7 @@ DiscoverySessionResultCallback callback) override; void UpdateFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; void RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) override;
diff --git a/device/bluetooth/bluetooth_adapter_mac.h b/device/bluetooth/bluetooth_adapter_mac.h index 0ff96757..61414cc 100644 --- a/device/bluetooth/bluetooth_adapter_mac.h +++ b/device/bluetooth/bluetooth_adapter_mac.h
@@ -198,14 +198,7 @@ void UpdateFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; // Start classic and/or low energy discovery sessions, according to the // filter. If a discovery session is already running the filter is updated.
diff --git a/device/bluetooth/bluetooth_adapter_mac.mm b/device/bluetooth/bluetooth_adapter_mac.mm index b6bea74..8e4a469 100644 --- a/device/bluetooth/bluetooth_adapter_mac.mm +++ b/device/bluetooth/bluetooth_adapter_mac.mm
@@ -429,54 +429,24 @@ UMABluetoothDiscoverySessionOutcome::SUCCESS)); } -void BluetoothAdapterMac::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - // Logic to soon be moved into parent adapter class - DVLOG(1) << __func__; +void BluetoothAdapterMac::StopScan(DiscoverySessionResultCallback callback) { + low_energy_discovery_manager_->StopDiscovery(); + for (const auto& device_id_object_pair : devices_) { + device_id_object_pair.second->ClearAdvertisementData(); + } - if (NumDiscoverySessions() > 1) { - // There are active sessions other than the one currently being removed. - DCHECK(IsDiscovering()); - callback.Run(); + if (classic_discovery_manager_->IsDiscovering() && + !classic_discovery_manager_->StopDiscovery()) { + DVLOG(1) << "Failed to stop classic discovery"; + // TODO: Provide a more precise error here. + std::move(callback).Run(/*is_error=*/true, + UMABluetoothDiscoverySessionOutcome::UNKNOWN); return; } - DCHECK_EQ(NumDiscoverySessions(), 1); - - // Default to dual discovery if |discovery_filter| is NULL. - BluetoothTransport transport = BLUETOOTH_TRANSPORT_DUAL; - if (discovery_filter) - transport = discovery_filter->GetTransport(); - - if (transport & BLUETOOTH_TRANSPORT_CLASSIC) { - if (!classic_discovery_manager_->StopDiscovery()) { - DVLOG(1) << "Failed to stop classic discovery"; - // TODO: Provide a more precise error here. - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::UNKNOWN); - return; - } - } - if (transport & BLUETOOTH_TRANSPORT_LE) { - low_energy_discovery_manager_->StopDiscovery(); - for (const auto& device_id_object_pair : devices_) { - device_id_object_pair.second->ClearAdvertisementData(); - } - } - DVLOG(1) << "Discovery stopped"; - callback.Run(); -} - -void BluetoothAdapterMac::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - NOTIMPLEMENTED(); - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED); + std::move(callback).Run(/*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::SUCCESS); } bool BluetoothAdapterMac::StartDiscovery(
diff --git a/device/bluetooth/bluetooth_adapter_mac_unittest.mm b/device/bluetooth/bluetooth_adapter_mac_unittest.mm index bf68952..61208af 100644 --- a/device/bluetooth/bluetooth_adapter_mac_unittest.mm +++ b/device/bluetooth/bluetooth_adapter_mac_unittest.mm
@@ -305,6 +305,9 @@ new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE)); std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2( new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE)); + // Adding uuid to first discovery session so that there is a change to be made + // when starting the second session. + discovery_filter->AddUUID(device::BluetoothUUID("1000")); adapter_mac_->StartDiscoverySessionWithFilter( std::move(discovery_filter), base::BindRepeating(
diff --git a/device/bluetooth/bluetooth_adapter_unittest.cc b/device/bluetooth/bluetooth_adapter_unittest.cc index 3b27496..46664bc5f 100644 --- a/device/bluetooth/bluetooth_adapter_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_unittest.cc
@@ -11,10 +11,14 @@ #include <utility> #include <vector> +#include "base/barrier_closure.h" #include "base/bind.h" +#include "base/bind_helpers.h" #include "base/memory/ref_counted.h" #include "base/run_loop.h" #include "base/test/bind_test_util.h" +#include "base/test/scoped_task_environment.h" +#include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" #include "device/bluetooth/bluetooth_common.h" #include "device/bluetooth/bluetooth_device.h" @@ -136,21 +140,111 @@ void TestOnStartDiscoverySession( std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { - discovery_sessions_holder_.push_back(std::move(discovery_session)); + ++callback_count_; + discovery_sessions_holder_.push(std::move(discovery_session)); } - void CleanupSessions() { discovery_sessions_.clear(); } + void OnStartDiscoverySessionQuitLoop( + base::Closure run_loop_quit, + std::unique_ptr<device::BluetoothDiscoverySession> discovery_session) { + ++callback_count_; + run_loop_quit.Run(); + discovery_sessions_holder_.push(std::move(discovery_session)); + } + + void OnRemoveDiscoverySession(base::Closure run_loop_quit) { + ++callback_count_; + run_loop_quit.Run(); + } + + void OnRemoveDiscoverySessionError(base::Closure run_loop_quit) { + ++callback_count_; + run_loop_quit.Run(); + } + + void StopDiscoverySession(base::Closure run_loop_quit) { + discovery_sessions_holder_.front()->Stop( + base::BindRepeating(&TestBluetoothAdapter::OnRemoveDiscoverySession, + this, run_loop_quit), + base::BindRepeating( + &TestBluetoothAdapter::OnRemoveDiscoverySessionError, this, + run_loop_quit)); + discovery_sessions_holder_.pop(); + } + + void StopAllDiscoverySessions(base::Closure run_loop_quit) { + int num_stop_requests = discovery_sessions_holder_.size(); + while (!discovery_sessions_holder_.empty()) { + discovery_sessions_holder_.front()->Stop( + base::BindLambdaForTesting( + [run_loop_quit, num_stop_requests, this]() { + num_requests_returned_++; + ++callback_count_; + if (num_requests_returned_ == num_stop_requests) { + num_requests_returned_ = 0; + run_loop_quit.Run(); + } + }), + base::BindRepeating( + &TestBluetoothAdapter::OnRemoveDiscoverySessionError, this, + run_loop_quit)); + discovery_sessions_holder_.pop(); + } + } + + void CleanupSessions() { + // clear discovery_sessions_holder_ + base::queue<std::unique_ptr<BluetoothDiscoverySession>> empty_queue; + std::swap(discovery_sessions_holder_, empty_queue); + } void InjectFilteredSession( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter) { StartDiscoverySessionWithFilter( std::move(discovery_filter), - base::Bind(&TestBluetoothAdapter::TestOnStartDiscoverySession, - base::Unretained(this)), - base::Bind(&TestBluetoothAdapter::TestErrorCallback, - base::Unretained(this))); + base::Bind(&TestBluetoothAdapter::TestOnStartDiscoverySession, this), + base::Bind(&TestBluetoothAdapter::TestErrorCallback, this)); } + void QueueStartRequests(base::Closure run_loop_quit, int num_requests) { + for (int i = 0; i < num_requests; ++i) { + StartDiscoverySession( + base::BindLambdaForTesting( + [run_loop_quit, num_requests, + this](std::unique_ptr<device::BluetoothDiscoverySession> + discovery_session) { + ++callback_count_; + num_requests_returned_++; + discovery_sessions_holder_.push(std::move(discovery_session)); + if (num_requests_returned_ == num_requests) { + num_requests_returned_ = 0; + run_loop_quit.Run(); + } + }), + base::Bind(&TestBluetoothAdapter::TestErrorCallback, this)); + }; + } + + void StartSessionWithFilter( + std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, + base::RepeatingClosure run_loop_quit) { + StartDiscoverySessionWithFilter( + std::move(discovery_filter), + base::Bind(&TestBluetoothAdapter::OnStartDiscoverySessionQuitLoop, this, + run_loop_quit), + base::DoNothing()); + } + + // |discovery_sessions_holder_| is used to hold unique pointers of Discovery + // Sessions so that the destructors don't get called and so we can test + // removing them + base::queue<std::unique_ptr<BluetoothDiscoverySession>> + discovery_sessions_holder_; + std::unique_ptr<BluetoothDiscoveryFilter> current_filter = + std::make_unique<BluetoothDiscoveryFilter>(); + int callback_count_ = 0; + bool is_discovering_ = false; + protected: ~TestBluetoothAdapter() override = default; @@ -159,33 +253,50 @@ void StartScanWithFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override { - std::move(callback).Run(false, - UMABluetoothDiscoverySessionOutcome::SUCCESS); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&TestBluetoothAdapter::SetFilter, this, + std::move(discovery_filter), std::move(callback))); } void UpdateFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override { - std::move(callback).Run(false, + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(&TestBluetoothAdapter::SetFilter, this, + std::move(discovery_filter), std::move(callback))); + } + + void SetFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, + DiscoverySessionResultCallback callback) { + is_discovering_ = true; + current_filter->CopyFrom(*discovery_filter.get()); + std::move(callback).Run(/*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS); } - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override {} + void StopScan(DiscoverySessionResultCallback callback) override { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&TestBluetoothAdapter::FakeOSStopScan, this, + std::move(callback))); + } - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override {} + void FakeOSStopScan(DiscoverySessionResultCallback callback) { + is_discovering_ = false; + std::move(callback).Run(/*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::SUCCESS); + } void RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) override {} - // |discovery_sessions_holder_| is used to hold unique pointers of Discovery - // Sessions so that the destructors don't get called. - std::vector<std::unique_ptr<BluetoothDiscoverySession>> - discovery_sessions_holder_; + int num_requests_returned_ = 0; + + private: + void PostDelayedTask(base::OnceClosure callback) { + base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, + std::move(callback)); + } }; class TestPairingDelegate : public BluetoothDevice::PairingDelegate { @@ -202,104 +313,223 @@ } // namespace -TEST(BluetoothAdapterTest, NoDefaultPairingDelegate) { - scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); +class BluetoothAdapterTest : public testing::Test { + public: + void SetUp() override { adapter_ = new TestBluetoothAdapter(); } + protected: + scoped_refptr<TestBluetoothAdapter> adapter_; + base::test::ScopedTaskEnvironment scoped_task_environment_; +}; + +TEST_F(BluetoothAdapterTest, NoDefaultPairingDelegate) { // Verify that when there is no registered pairing delegate, NULL is returned. - EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL); + EXPECT_TRUE(adapter_->DefaultPairingDelegate() == nullptr); } -TEST(BluetoothAdapterTest, OneDefaultPairingDelegate) { - scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); - +TEST_F(BluetoothAdapterTest, OneDefaultPairingDelegate) { // Verify that when there is one registered pairing delegate, it is returned. TestPairingDelegate delegate; - adapter->AddPairingDelegate(&delegate, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); + adapter_->AddPairingDelegate(&delegate, + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); - EXPECT_EQ(&delegate, adapter->DefaultPairingDelegate()); + EXPECT_EQ(&delegate, adapter_->DefaultPairingDelegate()); } -TEST(BluetoothAdapterTest, SamePriorityDelegates) { - scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); - +TEST_F(BluetoothAdapterTest, SamePriorityDelegates) { // Verify that when there are two registered pairing delegates of the same // priority, the first one registered is returned. TestPairingDelegate delegate1, delegate2; - adapter->AddPairingDelegate(&delegate1, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); - adapter->AddPairingDelegate(&delegate2, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); + adapter_->AddPairingDelegate(&delegate1, + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); + adapter_->AddPairingDelegate(&delegate2, + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); - EXPECT_EQ(&delegate1, adapter->DefaultPairingDelegate()); + EXPECT_EQ(&delegate1, adapter_->DefaultPairingDelegate()); // After unregistering the first, the second can be returned. - adapter->RemovePairingDelegate(&delegate1); + adapter_->RemovePairingDelegate(&delegate1); - EXPECT_EQ(&delegate2, adapter->DefaultPairingDelegate()); + EXPECT_EQ(&delegate2, adapter_->DefaultPairingDelegate()); } -TEST(BluetoothAdapterTest, HighestPriorityDelegate) { - scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); - +TEST_F(BluetoothAdapterTest, HighestPriorityDelegate) { // Verify that when there are two registered pairing delegates, the one with // the highest priority is returned. TestPairingDelegate delegate1, delegate2; - adapter->AddPairingDelegate(&delegate1, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); - adapter->AddPairingDelegate(&delegate2, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); + adapter_->AddPairingDelegate(&delegate1, + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); + adapter_->AddPairingDelegate( + &delegate2, BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_HIGH); - EXPECT_EQ(&delegate2, adapter->DefaultPairingDelegate()); + EXPECT_EQ(&delegate2, adapter_->DefaultPairingDelegate()); } -TEST(BluetoothAdapterTest, UnregisterDelegate) { - scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); - +TEST_F(BluetoothAdapterTest, UnregisterDelegate) { // Verify that after unregistering a delegate, NULL is returned. TestPairingDelegate delegate; - adapter->AddPairingDelegate(&delegate, - BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); - adapter->RemovePairingDelegate(&delegate); + adapter_->AddPairingDelegate(&delegate, + BluetoothAdapter::PAIRING_DELEGATE_PRIORITY_LOW); + adapter_->RemovePairingDelegate(&delegate); - EXPECT_TRUE(adapter->DefaultPairingDelegate() == NULL); + EXPECT_TRUE(adapter_->DefaultPairingDelegate() == nullptr); } -TEST(BluetoothAdapterTest, GetMergedDiscoveryFilterEmpty) { - scoped_refptr<BluetoothAdapter> adapter = new TestBluetoothAdapter(); +TEST_F(BluetoothAdapterTest, GetMergedDiscoveryFilterEmpty) { std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter; - discovery_filter = adapter->GetMergedDiscoveryFilter(); - EXPECT_TRUE(discovery_filter.get() == nullptr); - - discovery_filter = adapter->GetMergedDiscoveryFilterMasked(nullptr); - EXPECT_TRUE(discovery_filter.get() == nullptr); + discovery_filter = adapter_->GetMergedDiscoveryFilter(); + EXPECT_TRUE(discovery_filter->IsDefault()); } -TEST(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterRegular) { +TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterRegular) { scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter; - // make sure adapter have one session wihout filtering. - adapter->InjectFilteredSession(std::move(discovery_filter)); - // having one reglar session should result in no filter std::unique_ptr<BluetoothDiscoveryFilter> resulting_filter = - adapter->GetMergedDiscoveryFilter(); - EXPECT_TRUE(resulting_filter.get() == nullptr); + adapter_->GetMergedDiscoveryFilter(); + EXPECT_TRUE(resulting_filter->IsDefault()); - // omiting no filter when having one reglar session should result in no filter - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(nullptr); - EXPECT_TRUE(resulting_filter.get() == nullptr); - - adapter->CleanupSessions(); + adapter_->CleanupSessions(); } -TEST(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterRssi) { +TEST_F(BluetoothAdapterTest, TestQueueingLogic) { + BluetoothDiscoveryFilter* df = + new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE); + df->AddUUID(device::BluetoothUUID("1001")); + std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + BluetoothDiscoveryFilter* df2 = + new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE); + df->AddUUID(device::BluetoothUUID("1002")); + std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); + + // Start a discovery session + base::RunLoop run_loop1; + adapter_->StartSessionWithFilter(std::move(discovery_filter), + run_loop1.QuitClosure()); + + // Since the first request is still running we have not hit a single callback + EXPECT_EQ(0, adapter_->callback_count_); + + // While our first Discovery Session is starting queue up another one with a + // different filter. + base::RunLoop run_loop2; + adapter_->StartSessionWithFilter(std::move(discovery_filter2), + run_loop2.QuitClosure()); + + // Finish the first request. This should automatically start the queued + // request when completed. + run_loop1.Run(); + EXPECT_EQ(1, adapter_->callback_count_); + EXPECT_TRUE(adapter_->is_discovering_); + adapter_->callback_count_ = 0; + + // While our second discovery session is starting queue up 4 start requests + // with default filters. + base::RunLoop run_loop3; + adapter_->QueueStartRequests(run_loop3.QuitClosure(), 4); + + // Finish the second request. This should start the 4 queued requests. + run_loop2.Run(); + EXPECT_EQ(1, adapter_->callback_count_); + adapter_->callback_count_ = 0; + + // Queue up stop requests for the 2 started sessions. + base::RunLoop run_loop4; + adapter_->StopAllDiscoverySessions(base::DoNothing()); + // Confirm that no callbacks were hit and the filter has not changed. + EXPECT_EQ(0, adapter_->callback_count_); + EXPECT_FALSE(adapter_->current_filter->IsDefault()); + + // Run the 4 queued default requests. This should call all 4 callbacks from + // the start requests and automatically call the start the queue stop + // requests. These will short circuit and return immediately because the + // filter remains the default filter. + run_loop3.Run(); + EXPECT_EQ(6, adapter_->callback_count_); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + + adapter_->CleanupSessions(); +} + +TEST_F(BluetoothAdapterTest, ShortCircuitUpdateTest) { + auto discovery_filter_default1 = std::make_unique<BluetoothDiscoveryFilter>(); + BluetoothDiscoveryFilter* df = + new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE); + df->SetRSSI(-30); + std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df); + + base::RunLoop run_loop; + adapter_->StartSessionWithFilter(std::move(discovery_filter_default1), + run_loop.QuitClosure()); + run_loop.Run(); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(1, adapter_->callback_count_); + + // This time since there is no actual change being made the adapter should + // short circuit the callback immediately with success + auto discovery_filter_default2 = std::make_unique<BluetoothDiscoveryFilter>(); + adapter_->StartSessionWithFilter(std::move(discovery_filter_default2), + base::DoNothing()); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(2, adapter_->callback_count_); + + // This filter is different but is already covered under the default filter so + // it should still short circuit + adapter_->StartSessionWithFilter(std::move(discovery_filter), + base::DoNothing()); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(3, adapter_->callback_count_); + + // End the first discovery session which still short circuits because there is + // still a default session active + adapter_->StopDiscoverySession(base::DoNothing()); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(4, adapter_->callback_count_); + + // When removing the second default filter we should now actually update + // because discovery_filter is the only filter left + base::RunLoop run_loop2; + adapter_->StopDiscoverySession(run_loop2.QuitClosure()); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(4, adapter_->callback_count_); + run_loop2.Run(); + EXPECT_FALSE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(5, adapter_->callback_count_); + + // Adding another default but not finishing the update + base::RunLoop run_loop3; + auto discovery_filter_default3 = std::make_unique<BluetoothDiscoveryFilter>(); + adapter_->StartSessionWithFilter(std::move(discovery_filter_default3), + run_loop3.QuitClosure()); + EXPECT_FALSE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(5, adapter_->callback_count_); + + // Queue up another request that should short circuit and return success when + // default filter 3 updates + auto discovery_filter_default4 = std::make_unique<BluetoothDiscoveryFilter>(); + adapter_->StartSessionWithFilter(std::move(discovery_filter_default4), + base::DoNothing()); + EXPECT_FALSE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(5, adapter_->callback_count_); + + // Running the loop default filter 3 will update the the OS filter then then + // start processing the queued request. The queued request does not change + // the filter so it should automatically short circuit and return success. + run_loop3.Run(); + EXPECT_TRUE(adapter_->current_filter->IsDefault()); + EXPECT_EQ(7, adapter_->callback_count_); + + adapter_->CleanupSessions(); +} + +TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterRssi) { scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); int16_t resulting_rssi; uint16_t resulting_pathloss; @@ -316,35 +546,20 @@ std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); // Make sure adapter has one session without filtering. - adapter->InjectFilteredSession(std::move(discovery_filter)); + adapter_->InjectFilteredSession(std::move(discovery_filter)); // DO_NOTHING should have no impact - resulting_filter = adapter->GetMergedDiscoveryFilter(); + resulting_filter = adapter_->GetMergedDiscoveryFilter(); resulting_filter->GetRSSI(&resulting_rssi); EXPECT_EQ(-30, resulting_rssi); - // should not use df2 at all, as it's not associated with adapter yet - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df2); - resulting_filter->GetRSSI(&resulting_rssi); - EXPECT_EQ(-30, resulting_rssi); - - adapter->InjectFilteredSession(std::move(discovery_filter2)); + adapter_->InjectFilteredSession(std::move(discovery_filter2)); // result of merging two rssi values should be lower one - resulting_filter = adapter->GetMergedDiscoveryFilter(); + resulting_filter = adapter_->GetMergedDiscoveryFilter(); resulting_filter->GetRSSI(&resulting_rssi); EXPECT_EQ(-65, resulting_rssi); - // ommit bigger value, result should stay same - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df); - resulting_filter->GetRSSI(&resulting_rssi); - EXPECT_EQ(-65, resulting_rssi); - - // ommit lower value, result should change - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df2); - resulting_filter->GetRSSI(&resulting_rssi); - EXPECT_EQ(-30, resulting_rssi); - BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE); df3->SetPathloss(60); @@ -352,15 +567,15 @@ // when rssi and pathloss are merged, both should be cleared, because there is // no way to tell which filter will be more generic - adapter->InjectFilteredSession(std::move(discovery_filter3)); - resulting_filter = adapter->GetMergedDiscoveryFilter(); + adapter_->InjectFilteredSession(std::move(discovery_filter3)); + resulting_filter = adapter_->GetMergedDiscoveryFilter(); EXPECT_FALSE(resulting_filter->GetRSSI(&resulting_rssi)); EXPECT_FALSE(resulting_filter->GetPathloss(&resulting_pathloss)); - adapter->CleanupSessions(); + adapter_->CleanupSessions(); } -TEST(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterTransport) { +TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterTransport) { scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); std::unique_ptr<BluetoothDiscoveryFilter> resulting_filter; @@ -372,40 +587,32 @@ new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE); std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); - adapter->InjectFilteredSession(std::move(discovery_filter)); + adapter_->InjectFilteredSession(std::move(discovery_filter)); // Just one filter, make sure transport was properly rewritten - resulting_filter = adapter->GetMergedDiscoveryFilter(); + resulting_filter = adapter_->GetMergedDiscoveryFilter(); EXPECT_EQ(BLUETOOTH_TRANSPORT_CLASSIC, resulting_filter->GetTransport()); - adapter->InjectFilteredSession(std::move(discovery_filter2)); + adapter_->InjectFilteredSession(std::move(discovery_filter2)); // Two filters, should have OR of both transport's - resulting_filter = adapter->GetMergedDiscoveryFilter(); + resulting_filter = adapter_->GetMergedDiscoveryFilter(); EXPECT_EQ(BLUETOOTH_TRANSPORT_DUAL, resulting_filter->GetTransport()); - // When 1st filter is masked, 2nd filter transport should be returned. - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df); - EXPECT_EQ(BLUETOOTH_TRANSPORT_LE, resulting_filter->GetTransport()); - - // When 2nd filter is masked, 1st filter transport should be returned. - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df2); - EXPECT_EQ(BLUETOOTH_TRANSPORT_CLASSIC, resulting_filter->GetTransport()); - BluetoothDiscoveryFilter* df3 = new BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_LE); df3->CopyFrom(BluetoothDiscoveryFilter(BLUETOOTH_TRANSPORT_DUAL)); std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3); // Merging empty filter in should result in empty filter - adapter->InjectFilteredSession(std::move(discovery_filter3)); - resulting_filter = adapter->GetMergedDiscoveryFilter(); + adapter_->InjectFilteredSession(std::move(discovery_filter3)); + resulting_filter = adapter_->GetMergedDiscoveryFilter(); EXPECT_TRUE(resulting_filter->IsDefault()); - adapter->CleanupSessions(); + adapter_->CleanupSessions(); } -TEST(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterAllFields) { +TEST_F(BluetoothAdapterTest, MAYBE_GetMergedDiscoveryFilterAllFields) { scoped_refptr<TestBluetoothAdapter> adapter = new TestBluetoothAdapter(); int16_t resulting_rssi; std::set<device::BluetoothUUID> resulting_uuids; @@ -432,11 +639,11 @@ df3->AddUUID(device::BluetoothUUID("1003")); std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter3(df3); - adapter->InjectFilteredSession(std::move(discovery_filter)); - adapter->InjectFilteredSession(std::move(discovery_filter2)); - adapter->InjectFilteredSession(std::move(discovery_filter3)); + adapter_->InjectFilteredSession(std::move(discovery_filter)); + adapter_->InjectFilteredSession(std::move(discovery_filter2)); + adapter_->InjectFilteredSession(std::move(discovery_filter3)); std::unique_ptr<BluetoothDiscoveryFilter> resulting_filter = - adapter->GetMergedDiscoveryFilter(); + adapter_->GetMergedDiscoveryFilter(); resulting_filter->GetRSSI(&resulting_rssi); resulting_filter->GetUUIDs(resulting_uuids); EXPECT_TRUE(resulting_filter->GetTransport()); @@ -452,10 +659,7 @@ EXPECT_TRUE(resulting_uuids.find(device::BluetoothUUID("1020")) != resulting_uuids.end()); - resulting_filter = adapter->GetMergedDiscoveryFilterMasked(df); - EXPECT_EQ(BLUETOOTH_TRANSPORT_DUAL, resulting_filter->GetTransport()); - - adapter->CleanupSessions(); + adapter_->CleanupSessions(); } // TODO(scheib): Enable BluetoothTest fixture tests on all platforms. @@ -1075,9 +1279,9 @@ base::BindLambdaForTesting( // Note that we explicitly need to capture a pointer to the // underlying adapter, even though we pass |this| implicitly. This is - // because by the time this callback is invoked, |adapter_| is already + // because by the time this callback is invoked, |adapter| is already // set to null, but the pointed to adapter instance is still alive. So - // using the pointer is safe, but dereferencing |adapter_| crashes. + // using the pointer is safe, but dereferencing |adapter| crashes. [&] { error_callback_called = true; adapter->SetPowered(false, GetCallback(Call::NOT_EXPECTED),
diff --git a/device/bluetooth/bluetooth_adapter_win.cc b/device/bluetooth/bluetooth_adapter_win.cc index 5057a942..874194d 100644 --- a/device/bluetooth/bluetooth_adapter_win.cc +++ b/device/bluetooth/bluetooth_adapter_win.cc
@@ -68,7 +68,6 @@ initialized_(false), powered_(false), discovery_status_(NOT_DISCOVERING), - num_discovery_listeners_(0), force_update_device_for_test_(false), weak_ptr_factory_(this) {} @@ -129,38 +128,14 @@ discovery_status_ == DISCOVERY_STOPPING; } -static void RunDiscoverySessionErrorCallback( - base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)> - error_callback, - UMABluetoothDiscoverySessionOutcome outcome) { - std::move(error_callback).Run(outcome); -} - void BluetoothAdapterWin::DiscoveryStarted(bool success) { discovery_status_ = success ? DISCOVERING : NOT_DISCOVERING; - for (auto& callbacks : on_start_discovery_callbacks_) { - if (success) - ui_task_runner_->PostTask(FROM_HERE, callbacks.first); - else - ui_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(&RunDiscoverySessionErrorCallback, - std::move(callbacks.second), - UMABluetoothDiscoverySessionOutcome::UNKNOWN)); - } - num_discovery_listeners_ = on_start_discovery_callbacks_.size(); - on_start_discovery_callbacks_.clear(); + std::move(discovery_changed_callback_) + .Run(/*is_error=*/!success, UMABluetoothDiscoverySessionOutcome::UNKNOWN); if (success) { for (auto& observer : observers_) observer.AdapterDiscoveringChanged(this, true); - - // If there are stop discovery requests, post the stop discovery again. - MaybePostStopDiscoveryTask(); - } else if (!on_stop_discovery_callbacks_.empty()) { - // If there are stop discovery requests but start discovery has failed, - // notify that stop discovery has been complete. - DiscoveryStopped(); } } @@ -168,20 +143,11 @@ discovered_devices_.clear(); bool was_discovering = IsDiscovering(); discovery_status_ = NOT_DISCOVERING; - for (std::vector<base::Closure>::const_iterator iter = - on_stop_discovery_callbacks_.begin(); - iter != on_stop_discovery_callbacks_.end(); - ++iter) { - ui_task_runner_->PostTask(FROM_HERE, *iter); - } - num_discovery_listeners_ = 0; - on_stop_discovery_callbacks_.clear(); + std::move(discovery_changed_callback_) + .Run(/*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS); if (was_discovering) for (auto& observer : observers_) observer.AdapterDiscoveringChanged(this, false); - - // If there are start discovery requests, post the start discovery again. - MaybePostStartDiscoveryTask(); } BluetoothAdapter::UUIDList BluetoothAdapterWin::GetUUIDs() const { @@ -324,75 +290,31 @@ std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) { auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - // If the status is DISCOVERY_STOPPING then we then we must wait for the OS - // to complete that operation before starting a new discovery session. - // A new call to StartScanWithFilter is queued to perform this operation. - // The |discovery_filter| parameter is currently ignored so nullptr can be - // passed instead. This will be simplified when the RemoveDiscoverySession - // workflow is refactored in an upcoming CL. - if (discovery_status_ == DISCOVERY_STOPPING) { - on_stop_discovery_callbacks_.push_back(base::BindRepeating( - &BluetoothAdapterWin::StartScanWithFilter, base::Unretained(this), - nullptr, copyable_callback)); - return; - } DCHECK(discovery_status_ == DISCOVERING || discovery_status_ == DISCOVERY_STARTING); if (discovery_status_ == DISCOVERING) { - num_discovery_listeners_++; copyable_callback.Run(false, UMABluetoothDiscoverySessionOutcome::SUCCESS); return; } - on_start_discovery_callbacks_.push_back(std::make_pair( - base::BindRepeating(copyable_callback, false, - UMABluetoothDiscoverySessionOutcome::SUCCESS), - base::BindOnce(copyable_callback, true))); } void BluetoothAdapterWin::StartScanWithFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) { - auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - - // If the status is DISCOVERING already then this call was in the - // on_stop_discovery_callbacks_ queue and was called after another StartScan - // in the same queue. Now that the queue is already started we simply have to - // update the filter. This will be cleaned up completely when - // RemoveDiscoveryFilter is refactored. - if (discovery_status_ == DISCOVERING) { - UpdateFilter(std::move(discovery_filter), std::move(callback)); - return; - } - - on_start_discovery_callbacks_.push_back(std::make_pair( - base::BindRepeating(copyable_callback, false, - UMABluetoothDiscoverySessionOutcome::SUCCESS), - base::BindOnce(copyable_callback, true))); + discovery_changed_callback_ = std::move(callback); MaybePostStartDiscoveryTask(); } -void BluetoothAdapterWin::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { +void BluetoothAdapterWin::StopScan(DiscoverySessionResultCallback callback) { if (discovery_status_ == NOT_DISCOVERING) { - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE); + std::move(callback).Run(/*is_error=*/true, + UMABluetoothDiscoverySessionOutcome::NOT_ACTIVE); return; } - on_stop_discovery_callbacks_.push_back(callback); + discovery_changed_callback_ = std::move(callback); MaybePostStopDiscoveryTask(); } -void BluetoothAdapterWin::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - NOTIMPLEMENTED(); - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::NOT_IMPLEMENTED); -} - void BluetoothAdapterWin::Init() { ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); socket_thread_ = BluetoothSocketThread::Get(); @@ -417,8 +339,7 @@ } void BluetoothAdapterWin::MaybePostStartDiscoveryTask() { - if (discovery_status_ == NOT_DISCOVERING && - !on_start_discovery_callbacks_.empty()) { + if (discovery_status_ == NOT_DISCOVERING) { discovery_status_ = DISCOVERY_STARTING; task_manager_->PostStartDiscoveryTask(); } @@ -428,18 +349,6 @@ if (discovery_status_ != DISCOVERING) return; - if (on_stop_discovery_callbacks_.size() < num_discovery_listeners_) { - for (std::vector<base::Closure>::const_iterator iter = - on_stop_discovery_callbacks_.begin(); - iter != on_stop_discovery_callbacks_.end(); - ++iter) { - ui_task_runner_->PostTask(FROM_HERE, *iter); - } - num_discovery_listeners_ -= on_stop_discovery_callbacks_.size(); - on_stop_discovery_callbacks_.clear(); - return; - } - discovery_status_ = DISCOVERY_STOPPING; task_manager_->PostStopDiscoveryTask(); }
diff --git a/device/bluetooth/bluetooth_adapter_win.h b/device/bluetooth/bluetooth_adapter_win.h index 6c69ca82..5375000 100644 --- a/device/bluetooth/bluetooth_adapter_win.h +++ b/device/bluetooth/bluetooth_adapter_win.h
@@ -122,14 +122,7 @@ void StartScanWithFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; void Init(); void InitForTest( @@ -149,10 +142,7 @@ DiscoveryStatus discovery_status_; std::unordered_set<std::string> discovered_devices_; - std::vector<std::pair<base::Closure, DiscoverySessionErrorCallback>> - on_start_discovery_callbacks_; - std::vector<base::Closure> on_stop_discovery_callbacks_; - size_t num_discovery_listeners_; + DiscoverySessionResultCallback discovery_changed_callback_; scoped_refptr<BluetoothSocketThread> socket_thread_; scoped_refptr<BluetoothTaskManagerWin> task_manager_;
diff --git a/device/bluetooth/bluetooth_adapter_win_unittest.cc b/device/bluetooth/bluetooth_adapter_win_unittest.cc index c7b0418..0fa8034 100644 --- a/device/bluetooth/bluetooth_adapter_win_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_win_unittest.cc
@@ -73,15 +73,15 @@ void RunInitCallback() { init_callback_called_ = true; } - // This vector is used to store discovery sessions after a successful start - // so the destructor is not called. - std::vector<std::unique_ptr<BluetoothDiscoverySession>> + // This queue is used to store discovery sessions after a successful start so + // we can test stopping discovery and so the destructor is not called + base::queue<std::unique_ptr<BluetoothDiscoverySession>> active_discovery_sessions_; void DiscoverySessionCallbackPassthrough( const base::RepeatingClosure& callback, std::unique_ptr<BluetoothDiscoverySession> new_session) { - active_discovery_sessions_.push_back(std::move(new_session)); + active_discovery_sessions_.push(std::move(new_session)); callback.Run(); } @@ -100,6 +100,10 @@ num_stop_discovery_error_callbacks_++; } + void IncrementNumStopErrorCallbacks() { + ++num_stop_discovery_error_callbacks_; + } + typedef base::OnceCallback<void(UMABluetoothDiscoverySessionOutcome)> DiscoverySessionErrorCallback; @@ -118,11 +122,10 @@ base::Unretained(this))); } - void CallRemoveDiscoverySession( - const base::RepeatingClosure& callback, - DiscoverySessionErrorCallback error_callback) { - adapter_win_->RemoveDiscoverySession(nullptr, callback, - std::move(error_callback)); + void StopTopDiscoverySession(const base::RepeatingClosure& callback, + ErrorCallback error_callback) { + active_discovery_sessions_.front()->Stop(callback, error_callback); + active_discovery_sessions_.pop(); } protected: @@ -231,8 +234,12 @@ for (int i = 0; i < num_discoveries; i++) { CallStartDiscoverySession(); } + // Fake callback from OS for initial start call. adapter_win_->DiscoveryStarted(false); - ui_task_runner_->RunPendingTasks(); + // Fake callback from OS for second call which includes the 4 remaining starts + // calls. + adapter_win_->DiscoveryStarted(false); + EXPECT_FALSE(adapter_->IsDiscovering()); EXPECT_EQ(num_discoveries, num_start_discovery_error_callbacks_); EXPECT_EQ(0, observer_.discovering_changed_count()); @@ -276,11 +283,11 @@ CallStartDiscoverySession(); adapter_win_->DiscoveryStarted(true); ui_task_runner_->ClearPendingTasks(); - CallRemoveDiscoverySession( + StopTopDiscoverySession( base::BindRepeating( &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, base::Unretained(this)), - DiscoverySessionErrorCallback()); + ErrorCallback()); EXPECT_TRUE(adapter_->IsDiscovering()); EXPECT_EQ(0, num_stop_discovery_callbacks_); bluetooth_task_runner_->ClearPendingTasks(); @@ -301,20 +308,20 @@ ui_task_runner_->RunPendingTasks(); bluetooth_task_runner_->ClearPendingTasks(); for (int i = 0; i < num_discoveries - 1; i++) { - CallRemoveDiscoverySession( + StopTopDiscoverySession( base::BindRepeating( &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, base::Unretained(this)), - DiscoverySessionErrorCallback()); + ErrorCallback()); EXPECT_FALSE(bluetooth_task_runner_->HasPendingTask()); ui_task_runner_->RunPendingTasks(); EXPECT_EQ(i + 1, num_stop_discovery_callbacks_); } - CallRemoveDiscoverySession( + StopTopDiscoverySession( base::BindRepeating( &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, base::Unretained(this)), - DiscoverySessionErrorCallback()); + ErrorCallback()); EXPECT_EQ(1u, bluetooth_task_runner_->NumPendingTasks()); EXPECT_TRUE(adapter_->IsDiscovering()); adapter_win_->DiscoveryStopped(); @@ -331,17 +338,17 @@ CallStartDiscoverySession(); ui_task_runner_->RunPendingTasks(); bluetooth_task_runner_->ClearPendingTasks(); - CallRemoveDiscoverySession( + StopTopDiscoverySession( base::BindRepeating( &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, base::Unretained(this)), - DiscoverySessionErrorCallback()); + ErrorCallback()); EXPECT_FALSE(bluetooth_task_runner_->HasPendingTask()); - CallRemoveDiscoverySession( + StopTopDiscoverySession( base::BindRepeating( &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, base::Unretained(this)), - DiscoverySessionErrorCallback()); + ErrorCallback()); EXPECT_EQ(1u, bluetooth_task_runner_->NumPendingTasks()); } @@ -351,7 +358,7 @@ adapter_win_->DiscoveryStarted(true); EXPECT_TRUE(adapter_->IsDiscovering()); ui_task_runner_->RunPendingTasks(); - active_discovery_sessions_[0]->Stop( + active_discovery_sessions_.front()->Stop( base::BindRepeating( &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, base::Unretained(this)), @@ -366,74 +373,19 @@ TEST_F(BluetoothAdapterWinTest, StartDiscoveryBeforeDiscoveryStopped) { CallStartDiscoverySession(); + adapter_win_->DiscoveryStarted(true); ui_task_runner_->RunPendingTasks(); - CallRemoveDiscoverySession(base::RepeatingClosure(), - DiscoverySessionErrorCallback()); + StopTopDiscoverySession( + base::BindRepeating( + &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, + base::Unretained(this)), + ErrorCallback()); CallStartDiscoverySession(); bluetooth_task_runner_->ClearPendingTasks(); adapter_win_->DiscoveryStopped(); EXPECT_EQ(1u, bluetooth_task_runner_->NumPendingTasks()); } -TEST_F(BluetoothAdapterWinTest, StopDiscoveryWithoutStartDiscovery) { - CallRemoveDiscoverySession( - base::RepeatingClosure(), - base::BindOnce( - &BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks, - base::Unretained(this))); - EXPECT_EQ(1, num_stop_discovery_error_callbacks_); -} - -TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStarted) { - CallStartDiscoverySession(); - CallRemoveDiscoverySession( - base::RepeatingClosure(), - base::BindOnce( - &BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks, - base::Unretained(this))); - bluetooth_task_runner_->ClearPendingTasks(); - adapter_win_->DiscoveryStarted(true); - EXPECT_EQ(1u, bluetooth_task_runner_->NumPendingTasks()); -} - -TEST_F(BluetoothAdapterWinTest, StartAndStopBeforeDiscoveryStarted) { - int num_expected_start_discoveries = 3; - int num_expected_stop_discoveries = 2; - for (int i = 0; i < num_expected_start_discoveries; i++) { - CallStartDiscoverySession(); - } - for (int i = 0; i < num_expected_stop_discoveries; i++) { - CallRemoveDiscoverySession( - base::BindRepeating( - &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, - base::Unretained(this)), - base::BindOnce( - &BluetoothAdapterWinTest::IncrementNumStopDiscoveryErrorCallbacks, - base::Unretained(this))); - } - bluetooth_task_runner_->ClearPendingTasks(); - adapter_win_->DiscoveryStarted(true); - EXPECT_FALSE(bluetooth_task_runner_->HasPendingTask()); - ui_task_runner_->RunPendingTasks(); - EXPECT_EQ(num_expected_start_discoveries, num_start_discovery_callbacks_); - EXPECT_EQ(num_expected_stop_discoveries, num_stop_discovery_callbacks_); -} - -TEST_F(BluetoothAdapterWinTest, StopDiscoveryBeforeDiscoveryStartedAndFailed) { - CallStartDiscoverySession(); - CallRemoveDiscoverySession( - base::BindRepeating( - &BluetoothAdapterWinTest::IncrementNumStopDiscoveryCallbacks, - base::Unretained(this)), - DiscoverySessionErrorCallback()); - ui_task_runner_->ClearPendingTasks(); - adapter_win_->DiscoveryStarted(false); - ui_task_runner_->RunPendingTasks(); - EXPECT_EQ(1, num_start_discovery_error_callbacks_); - EXPECT_EQ(1, num_stop_discovery_callbacks_); - EXPECT_EQ(0, observer_.discovering_changed_count()); -} - TEST_F(BluetoothAdapterWinTest, DevicesPolled) { std::vector<std::unique_ptr<BluetoothTaskManagerWin::DeviceState>> devices; devices.push_back(std::make_unique<BluetoothTaskManagerWin::DeviceState>());
diff --git a/device/bluetooth/bluetooth_adapter_winrt.cc b/device/bluetooth/bluetooth_adapter_winrt.cc index 8cd58d3..002eca6 100644 --- a/device/bluetooth/bluetooth_adapter_winrt.cc +++ b/device/bluetooth/bluetooth_adapter_winrt.cc
@@ -957,22 +957,8 @@ UMABluetoothDiscoverySessionOutcome::SUCCESS)); } -void BluetoothAdapterWinrt::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - if (NumDiscoverySessions() == 0) { - ui_task_runner_->PostTask( - FROM_HERE, - base::BindOnce(std::move(error_callback), - UMABluetoothDiscoverySessionOutcome::UNKNOWN)); - return; - } - - if (NumDiscoverySessions() > 1) { - ui_task_runner_->PostTask(FROM_HERE, std::move(callback)); - return; - } +void BluetoothAdapterWinrt::StopScan(DiscoverySessionResultCallback callback) { + DCHECK_EQ(NumDiscoverySessions(), 0); RemoveAdvertisementReceivedHandler(); HRESULT hr = ble_advertisement_watcher_->Stop(); @@ -981,7 +967,7 @@ << logging::SystemErrorCodeToString(hr); ui_task_runner_->PostTask( FROM_HERE, - base::BindOnce(std::move(error_callback), + base::BindOnce(std::move(callback), /*is_error=*/true, UMABluetoothDiscoverySessionOutcome::UNKNOWN)); return; } @@ -989,14 +975,9 @@ for (auto& device : devices_) device.second->ClearAdvertisementData(); ble_advertisement_watcher_.Reset(); - ui_task_runner_->PostTask(FROM_HERE, std::move(callback)); -} - -void BluetoothAdapterWinrt::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - NOTIMPLEMENTED(); + ui_task_runner_->PostTask( + FROM_HERE, base::BindOnce(std::move(callback), /*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::SUCCESS)); } void BluetoothAdapterWinrt::RemovePairingDelegateInternal(
diff --git a/device/bluetooth/bluetooth_adapter_winrt.h b/device/bluetooth/bluetooth_adapter_winrt.h index 87dcade..ba36fa18 100644 --- a/device/bluetooth/bluetooth_adapter_winrt.h +++ b/device/bluetooth/bluetooth_adapter_winrt.h
@@ -98,14 +98,7 @@ void StartScanWithFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; void RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) override;
diff --git a/device/bluetooth/bluetooth_discovery_filter.cc b/device/bluetooth/bluetooth_discovery_filter.cc index effad3a..f591b63 100644 --- a/device/bluetooth/bluetooth_discovery_filter.cc +++ b/device/bluetooth/bluetooth_discovery_filter.cc
@@ -12,6 +12,10 @@ namespace device { +BluetoothDiscoveryFilter::BluetoothDiscoveryFilter() { + SetTransport(BluetoothTransport::BLUETOOTH_TRANSPORT_DUAL); +} + BluetoothDiscoveryFilter::BluetoothDiscoveryFilter( BluetoothTransport transport) { SetTransport(transport); @@ -76,11 +80,11 @@ const BluetoothDiscoveryFilter& filter) { transport_ = filter.transport_; + uuids_.clear(); if (filter.uuids_.size()) { for (const auto& uuid : filter.uuids_) AddUUID(*uuid); - } else - uuids_.clear(); + } rssi_ = filter.rssi_; pathloss_ = filter.pathloss_; @@ -140,9 +144,8 @@ bool BluetoothDiscoveryFilter::Equals( const BluetoothDiscoveryFilter& other) const { if ((rssi_.has_value() != other.rssi_.has_value()) || - (rssi_ && other.rssi_ && *rssi_ != *other.rssi_)) { + (rssi_ && other.rssi_ && *rssi_ != *other.rssi_)) return false; - } if ((pathloss_.has_value() != other.pathloss_.has_value()) || (pathloss_ && other.pathloss_ && *pathloss_ != *other.pathloss_)) {
diff --git a/device/bluetooth/bluetooth_discovery_filter.h b/device/bluetooth/bluetooth_discovery_filter.h index 5e41fd32..7749635 100644 --- a/device/bluetooth/bluetooth_discovery_filter.h +++ b/device/bluetooth/bluetooth_discovery_filter.h
@@ -22,6 +22,7 @@ // Used to keep a discovery filter that can be used to limit reported devices. class DEVICE_BLUETOOTH_EXPORT BluetoothDiscoveryFilter { public: + BluetoothDiscoveryFilter(); BluetoothDiscoveryFilter(BluetoothTransport transport); ~BluetoothDiscoveryFilter();
diff --git a/device/bluetooth/bluetooth_discovery_session.cc b/device/bluetooth/bluetooth_discovery_session.cc index d924ef9..84401b75 100644 --- a/device/bluetooth/bluetooth_discovery_session.cc +++ b/device/bluetooth/bluetooth_discovery_session.cc
@@ -26,7 +26,6 @@ BluetoothDiscoverySession::~BluetoothDiscoverySession() { if (active_) { Stop(base::DoNothing(), base::DoNothing()); - MarkAsInactive(); } } @@ -60,16 +59,17 @@ weak_ptr_factory_.GetWeakPtr()); // Create a callback that runs - // BluetoothDiscoverySession::DeactivateDiscoverySession if the session still - // exists, but always runs success_callback. + // BluetoothDiscoverySession::DeactivateDiscoverySession if the session + // still exists, but always runs success_callback. base::Closure discovery_session_removed_callback = base::Bind(&BluetoothDiscoverySession::OnDiscoverySessionRemoved, weak_ptr_factory_.GetWeakPtr(), deactive_discovery_session, success_callback); adapter_->RemoveDiscoverySession( - discovery_filter_.get(), discovery_session_removed_callback, + this, discovery_session_removed_callback, base::Bind(&BluetoothDiscoverySession::OnDiscoverySessionRemovalFailed, weak_ptr_factory_.GetWeakPtr(), error_callback)); + MarkAsInactive(); } // static @@ -105,25 +105,6 @@ if (!active_) return; active_ = false; - adapter_->DiscoverySessionBecameInactive(this); -} - -static void IgnoreDiscoveryOutcome( - const base::Closure& error_callback, - UMABluetoothDiscoverySessionOutcome outcome) { - error_callback.Run(); -} - -void BluetoothDiscoverySession::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - const ErrorCallback& error_callback) { - discovery_filter_ = std::move(discovery_filter); - // BluetoothDiscoverySession::SetDiscoveryFilter is only used from a private - // extension API, so we don't bother histogramming its failures. - adapter_->SetDiscoveryFilter( - adapter_->GetMergedDiscoveryFilter(), callback, - base::Bind(&IgnoreDiscoveryOutcome, error_callback)); } const BluetoothDiscoveryFilter* BluetoothDiscoverySession::GetDiscoveryFilter()
diff --git a/device/bluetooth/bluetooth_discovery_session.h b/device/bluetooth/bluetooth_discovery_session.h index 0415c3a..e3ab280f 100644 --- a/device/bluetooth/bluetooth_discovery_session.h +++ b/device/bluetooth/bluetooth_discovery_session.h
@@ -62,11 +62,6 @@ virtual void Stop(const base::Closure& callback, const ErrorCallback& error_callback); - virtual void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - const ErrorCallback& error_callback); - virtual const BluetoothDiscoveryFilter* GetDiscoveryFilter() const; base::WeakPtr<BluetoothDiscoverySession> GetWeakPtr();
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc index e3a7f3e0..ba1c130 100644 --- a/device/bluetooth/bluez/bluetooth_adapter_bluez.cc +++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.cc
@@ -262,8 +262,7 @@ : init_callback_(std::move(init_callback)), initialized_(false), dbus_is_shutdown_(false), - discovery_request_pending_(false), - force_deactivate_discovery_(false) { + weak_ptr_factory_(this) { ui_task_runner_ = base::ThreadTaskRunnerHandle::Get(); socket_thread_ = device::BluetoothSocketThread::Get(); @@ -454,7 +453,6 @@ bluez::BluezDBusManager::Get() ->GetBluetoothAdapterClient() ->GetProperties(object_path_); - return properties->discovering.value(); } @@ -1140,20 +1138,10 @@ // us, reset the count to 0. BLUETOOTH_LOG(EVENT) << "Discovering changed: " << discovering; if (!discovering && NumDiscoverySessions() > 0) { - if (discovery_request_pending_) { - // If there is discovery request pending, this is guaranteed to be a - // Stop() of the last discovery session (NumDiscoverySessions() == 1). - // That last Stop() may fail due to adapter not being present, in which - // case there will be dangling discovery count. So we are setting a flag - // so that the failing Stop() assumes that there is no more discovery - // session. - BLUETOOTH_LOG(DEBUG) << "Forcing to deactivate discovery."; - force_deactivate_discovery_ = true; - } else { - BLUETOOTH_LOG(DEBUG) << "Marking sessions as inactive."; - MarkDiscoverySessionsAsInactive(); - } + BLUETOOTH_LOG(DEBUG) << "Marking sessions as inactive."; + MarkDiscoverySessionsAsInactive(); } + for (auto& observer : observers_) observer.AdapterDiscoveringChanged(this, discovering); } @@ -1491,7 +1479,7 @@ void BluetoothAdapterBlueZ::UpdateFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) { - DCHECK_GT(NumDiscoverySessions(), 1); + DCHECK_GT(NumDiscoverySessions(), 0); if (!IsPresent()) { std::move(callback).Run( true, UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT); @@ -1499,38 +1487,14 @@ } BLUETOOTH_LOG(EVENT) << __func__; - if (discovery_request_pending_) { - // The pending request is either to stop a previous session or to start - // a new one. Either way, queue this one. - - BLUETOOTH_LOG(DEBUG) - << "Pending request to start/stop device discovery. Queueing " - << "request to start a new discovery session."; - discovery_request_queue_.push(std::move(callback)); - return; - } - - // If the old and new filter are both null then don't make the request, and - // just call the success callback. - // Do the same if the old and new filter are both not null and equal. - if ((!current_filter_ && !discovery_filter.get()) || - (current_filter_ && discovery_filter && - current_filter_->Equals(*discovery_filter))) { - std::move(callback).Run(false, - UMABluetoothDiscoverySessionOutcome::SUCCESS); - return; - } auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - // The adapter is already discovering. - DCHECK_GT(NumDiscoverySessions(), 1); // DCHECK(IsDiscovering()) is removed due to BlueZ bug // (https://crbug.com/822104). // TODO(sonnysasaka): Put it back here when BlueZ bug is fixed. - DCHECK(!discovery_request_pending_); SetDiscoveryFilter( - GetMergedDiscoveryFilter(), + std::move(discovery_filter), base::BindRepeating(copyable_callback, /*is_error*/ false, UMABluetoothDiscoverySessionOutcome::SUCCESS), base::BindOnce(copyable_callback, true)); @@ -1546,21 +1510,7 @@ return; } - // This function should only be called if this is the first discovery session. - // Otherwise we should have called UpdateFilter. - DCHECK_EQ(NumDiscoverySessions(), 1); - BLUETOOTH_LOG(EVENT) << __func__; - if (discovery_request_pending_) { - // The pending request is either to stop a previous session or to start - // OnSetDiscoveryFilter new one. Either way, queue this one. - - BLUETOOTH_LOG(DEBUG) - << "Pending request to start/stop device discovery. Queueing " - << "request to start a new discovery session."; - discovery_request_queue_.push(std::move(callback)); - return; - } #if defined(OS_CHROMEOS) device::BluetoothAdapterFactory::BleScanParserCallback @@ -1584,9 +1534,7 @@ auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); - if (discovery_filter) { - discovery_request_pending_ = true; - + if (discovery_filter && !discovery_filter->IsDefault()) { std::unique_ptr<BluetoothDiscoveryFilter> df( new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_DUAL)); df->CopyFrom(*discovery_filter); @@ -1595,86 +1543,71 @@ base::BindRepeating( &BluetoothAdapterBlueZ::OnPreSetDiscoveryFilter, weak_ptr_factory_.GetWeakPtr(), - base::BindRepeating(copyable_callback, /*is_error*/ false, + base::BindRepeating(copyable_callback, /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS), base::BindRepeating(copyable_callback, true)), base::BindOnce( &BluetoothAdapterBlueZ::OnPreSetDiscoveryFilterError, weak_ptr_factory_.GetWeakPtr(), - base::BindRepeating(copyable_callback, /*is_error*/ false, + base::BindRepeating(copyable_callback, /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS), base::BindOnce(copyable_callback, true))); return; - } else { - current_filter_.reset(); } // This is the first request to start device discovery. - discovery_request_pending_ = true; bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->StartDiscovery( object_path_, base::BindRepeating( &BluetoothAdapterBlueZ::OnStartDiscovery, weak_ptr_factory_.GetWeakPtr(), - base::BindRepeating(copyable_callback, /*is_error*/ false, + base::BindRepeating(copyable_callback, /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS), base::BindRepeating(copyable_callback, true)), base::BindOnce( &BluetoothAdapterBlueZ::OnStartDiscoveryError, weak_ptr_factory_.GetWeakPtr(), - base::BindRepeating(copyable_callback, /*is_error*/ false, + base::BindRepeating(copyable_callback, /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS), base::BindOnce(copyable_callback, true))); } -void BluetoothAdapterBlueZ::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - if (!IsPresent()) { - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT); - return; - } - - BLUETOOTH_LOG(EVENT) << __func__; - // There are active sessions other than the one currently being removed. - if (NumDiscoverySessions() > 1) { - // DCHECK(IsDiscovering()) is removed due to BlueZ bug - // (https://crbug.com/822104). - // TODO(sonnysasaka): Put it back here when BlueZ bug is fixed. - DCHECK(!discovery_request_pending_); - - SetDiscoveryFilter(GetMergedDiscoveryFilterMasked(discovery_filter), - callback, std::move(error_callback)); - return; - } - - // If there is a pending request to BlueZ, then queue this request. - if (discovery_request_pending_) { - BLUETOOTH_LOG(DEBUG) - << "Pending request to start/stop device discovery. Queueing " - << "request to stop discovery session."; - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST); - return; - } - +void BluetoothAdapterBlueZ::StopScan(DiscoverySessionResultCallback callback) { #if defined(OS_CHROMEOS) ble_scan_parser_.reset(); #endif // defined(OS_CHROMEOS) - // There is exactly one active discovery session. Request BlueZ to stop - // discovery. - DCHECK_EQ(NumDiscoverySessions(), 1); - discovery_request_pending_ = true; + // Not having an adapter qualifies as not scanning so we callback a success + if (!IsPresent()) { + std::move(callback).Run( + /*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT); + return; + } + + BLUETOOTH_LOG(EVENT) << __func__; + + DCHECK_EQ(NumDiscoverySessions(), 0); + + if (!IsDiscovering()) { + std::move(callback).Run( + /*is_error=*/false, UMABluetoothDiscoverySessionOutcome::SUCCESS); + return; + } + + // Confirm that there are no more discovery sessions left. + DCHECK_EQ(NumDiscoverySessions(), 0); + auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); bluez::BluezDBusManager::Get()->GetBluetoothAdapterClient()->StopDiscovery( object_path_, - base::BindRepeating(&BluetoothAdapterBlueZ::OnStopDiscovery, - weak_ptr_factory_.GetWeakPtr(), callback), + base::BindRepeating( + &BluetoothAdapterBlueZ::OnStopDiscovery, + weak_ptr_factory_.GetWeakPtr(), + base::BindRepeating(copyable_callback, /*is_error=*/false, + UMABluetoothDiscoverySessionOutcome::SUCCESS)), base::BindOnce(&BluetoothAdapterBlueZ::OnStopDiscoveryError, weak_ptr_factory_.GetWeakPtr(), - std::move(error_callback))); + base::BindOnce(copyable_callback, /*is_error=*/true))); } void BluetoothAdapterBlueZ::SetDiscoveryFilter( @@ -1687,33 +1620,21 @@ return; } - // If the old and new filter are both null then don't make the request, and - // just call the success callback. - // Do the same if the old and new filter are both not null and equal. - if ((!current_filter_ && !discovery_filter.get()) || - (current_filter_ && discovery_filter && - current_filter_->Equals(*discovery_filter))) { - callback.Run(); - return; - } - - current_filter_ = std::move(discovery_filter); - bluez::BluetoothAdapterClient::DiscoveryFilter dbus_discovery_filter; - if (current_filter_.get()) { + if (discovery_filter.get() && !discovery_filter->IsDefault()) { uint16_t pathloss; int16_t rssi; uint8_t transport; std::set<device::BluetoothUUID> uuids; - if (current_filter_->GetPathloss(&pathloss)) + if (discovery_filter->GetPathloss(&pathloss)) dbus_discovery_filter.pathloss.reset(new uint16_t(pathloss)); - if (current_filter_->GetRSSI(&rssi)) + if (discovery_filter->GetRSSI(&rssi)) dbus_discovery_filter.rssi.reset(new int16_t(rssi)); - transport = current_filter_->GetTransport(); + transport = discovery_filter->GetTransport(); if (transport == device::BLUETOOTH_TRANSPORT_LE) { dbus_discovery_filter.transport.reset(new std::string("le")); } else if (transport == device::BLUETOOTH_TRANSPORT_CLASSIC) { @@ -1722,7 +1643,7 @@ dbus_discovery_filter.transport.reset(new std::string("auto")); } - current_filter_->GetUUIDs(uuids); + discovery_filter->GetUUIDs(uuids); if (uuids.size()) { dbus_discovery_filter.uuids = std::unique_ptr<std::vector<std::string>>( new std::vector<std::string>); @@ -1751,17 +1672,12 @@ DiscoverySessionErrorCallback error_callback) { // Report success on the original request and increment the count. BLUETOOTH_LOG(EVENT) << __func__; - DCHECK(discovery_request_pending_); - discovery_request_pending_ = false; if (IsPresent()) { callback.Run(); } else { std::move(error_callback) .Run(UMABluetoothDiscoverySessionOutcome::ADAPTER_REMOVED); } - - // Try to add a new discovery session for each queued request. - ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterBlueZ::OnStartDiscoveryError( @@ -1773,63 +1689,30 @@ << ": Failed to start discovery: " << error_name << ": " << error_message; - DCHECK(discovery_request_pending_); - discovery_request_pending_ = false; - std::move(error_callback).Run(TranslateDiscoveryErrorToUMA(error_name)); - - // Try to add a new discovery session for each queued request. - ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterBlueZ::OnStopDiscovery(const base::Closure& callback) { // Report success on the original request and decrement the count. BLUETOOTH_LOG(EVENT) << __func__; - DCHECK(discovery_request_pending_); DCHECK_GE(NumDiscoverySessions(), 0); - discovery_request_pending_ = false; callback.Run(); - - force_deactivate_discovery_ = false; - - current_filter_.reset(); - - // Try to add a new discovery session for each queued request. - ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterBlueZ::OnStopDiscoveryError( DiscoverySessionErrorCallback error_callback, const std::string& error_name, const std::string& error_message) { - DCHECK(discovery_request_pending_); - discovery_request_pending_ = false; - - if (force_deactivate_discovery_) { - BLUETOOTH_LOG(DEBUG) << "Forced to mark sessions as inactive"; - force_deactivate_discovery_ = false; - MarkDiscoverySessionsAsInactive(); - // Do not consider this situation as error as the error from Stop() - // discovery session was expected. So log with DEBUG instead of ERROR. - BLUETOOTH_LOG(DEBUG) << object_path_.value() - << ": Failed to stop discovery: " << error_name << ": " - << error_message; - } else { - BLUETOOTH_LOG(ERROR) << object_path_.value() - << ": Failed to stop discovery: " << error_name << ": " - << error_message; - } + BLUETOOTH_LOG(ERROR) << object_path_.value() + << ": Failed to stop discovery: " << error_name << ": " + << error_message; std::move(error_callback).Run(TranslateDiscoveryErrorToUMA(error_name)); - - // Try to add a new discovery session for each queued request. - ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterBlueZ::OnPreSetDiscoveryFilter( const base::Closure& callback, DiscoverySessionErrorCallback error_callback) { - DCHECK(discovery_request_pending_); auto copyable_error_callback = base::AdaptCallbackForRepeating(std::move(error_callback)); @@ -1850,12 +1733,7 @@ BLUETOOTH_LOG(ERROR) << object_path_.value() << ": Failed to pre set discovery filter."; - discovery_request_pending_ = false; - std::move(error_callback).Run(outcome); - - // Try to add a new discovery session for each queued request. - ProcessQueuedDiscoveryRequests(); } void BluetoothAdapterBlueZ::OnSetDiscoveryFilter( @@ -1890,33 +1768,6 @@ BLUEZ_DBUS_FAILED_MAYBE_UNSUPPORTED_TRANSPORT; } std::move(error_callback).Run(outcome); - - // Try to add a new discovery session for each queued request. - ProcessQueuedDiscoveryRequests(); -} - -void BluetoothAdapterBlueZ::ProcessQueuedDiscoveryRequests() { - while (!discovery_request_queue_.empty()) { - BLUETOOTH_LOG(EVENT) << "Process queued discovery request."; - DiscoverySessionResultCallback callback = - std::move(discovery_request_queue_.front()); - discovery_request_queue_.pop(); - - if (NumDiscoverySessions() > 1) { - std::unique_ptr<BluetoothDiscoveryFilter> current_filter = - BluetoothAdapter::GetMergedDiscoveryFilter(); - UpdateFilter(std::move(current_filter), std::move(callback)); - } else { - std::unique_ptr<BluetoothDiscoveryFilter> current_filter = - BluetoothAdapter::GetMergedDiscoveryFilter(); - StartScanWithFilter(std::move(current_filter), std::move(callback)); - } - // If the queued request resulted in a pending call, then let it - // asynchonously process the remaining queued requests once the pending - // call returns. - if (discovery_request_pending_) - return; - } } void BluetoothAdapterBlueZ::UpdateRegisteredApplication(
diff --git a/device/bluetooth/bluez/bluetooth_adapter_bluez.h b/device/bluetooth/bluez/bluetooth_adapter_bluez.h index 3de2d943..cdd92374 100644 --- a/device/bluetooth/bluez/bluetooth_adapter_bluez.h +++ b/device/bluetooth/bluez/bluetooth_adapter_bluez.h
@@ -377,14 +377,11 @@ void UpdateFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - device::BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; void SetDiscoveryFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + DiscoverySessionErrorCallback error_callback); // Called by dbus:: on completion of the D-Bus method call to start discovery. void OnStartDiscovery(const base::Closure& callback, @@ -431,12 +428,6 @@ // remain. void RemoveProfile(const device::BluetoothUUID& uuid); - // Processes the queued discovery requests. For each DiscoveryParamTuple in - // the queue, this method will try to add a new discovery session. This method - // is called whenever a pending D-Bus call to start or stop discovery has - // ended (with either success or failure). - void ProcessQueuedDiscoveryRequests(); - // Make the call to GattManager1 to unregister then re-register the GATT // application. If the ignore_unregister_failure flag is set, we attempt to // register even if the initial unregister call fails. @@ -484,13 +475,6 @@ // Set in |Shutdown()|, makes IsPresent()| return false. bool dbus_is_shutdown_; - // True, if there is a pending request to start or stop discovery. - bool discovery_request_pending_; - - // If true that means the last pending stop discovery operation should assume - // that the discovery sessions have been deactivated even though it failed. - bool force_deactivate_discovery_; - // List of queued requests to add new discovery sessions. While there is a // pending request to BlueZ to start or stop discovery, many requests from // within Chrome to start or stop discovery sessions may occur. We only @@ -523,8 +507,6 @@ std::map<device::BluetoothUUID, std::vector<RegisterProfileCompletionPair>*> profile_queues_; - std::unique_ptr<device::BluetoothDiscoveryFilter> current_filter_; - // List of GATT services that are owned by this adapter. std::map<dbus::ObjectPath, std::unique_ptr<BluetoothLocalGattServiceBlueZ>> owned_gatt_services_;
diff --git a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc index c411b3f..4efd523 100644 --- a/device/bluetooth/bluez/bluetooth_bluez_unittest.cc +++ b/device/bluetooth/bluez/bluetooth_bluez_unittest.cc
@@ -144,7 +144,7 @@ ASSERT_EQ(1, callback_count_); } discovery_sessions_.clear(); - adapter_ = nullptr; + adapter_.reset(); bluez::BluezDBusManager::Shutdown(); } @@ -249,7 +249,6 @@ while (!observer.device_removed_count() && observer.last_device_address() != address) base::RunLoop().Run(); - discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); base::RunLoop().Run(); ASSERT_EQ(1, callback_count_); @@ -665,7 +664,6 @@ // AdapterDiscoveringChanged method to be called and no longer to be // discovering, TestBluetoothAdapterObserver observer(adapter_); - discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); base::RunLoop().Run(); EXPECT_EQ(1, callback_count_); @@ -1203,120 +1201,6 @@ EXPECT_FALSE(discovery_sessions_[0]->IsActive()); } -TEST_F(BluetoothBlueZTest, QueuedDiscoveryRequests) { - GetAdapter(); - - adapter_->SetPowered(true, GetCallback(), GetErrorCallback()); - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - EXPECT_TRUE(adapter_->IsPowered()); - callback_count_ = 0; - - TestBluetoothAdapterObserver observer(adapter_); - - EXPECT_EQ(0, observer.discovering_changed_count()); - EXPECT_FALSE(observer.last_discovering()); - EXPECT_FALSE(adapter_->IsDiscovering()); - - // Request to start discovery. The call should be pending. - adapter_->StartDiscoverySession( - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - GetErrorCallback()); - EXPECT_EQ(0, callback_count_); - - fake_bluetooth_device_client_->EndDiscoverySimulation( - dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath)); - - // The underlying adapter has started discovery, but our call hasn't returned - // yet. - EXPECT_EQ(1, observer.discovering_changed_count()); - EXPECT_TRUE(observer.last_discovering()); - EXPECT_TRUE(adapter_->IsDiscovering()); - EXPECT_TRUE(discovery_sessions_.empty()); - - // Request to start discovery twice. These should get queued and there should - // be no change in state. - for (int i = 0; i < 2; i++) { - adapter_->StartDiscoverySession( - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - GetErrorCallback()); - } - EXPECT_EQ(0, callback_count_); - EXPECT_EQ(0, error_callback_count_); - EXPECT_EQ(1, observer.discovering_changed_count()); - EXPECT_TRUE(observer.last_discovering()); - EXPECT_TRUE(adapter_->IsDiscovering()); - EXPECT_TRUE(discovery_sessions_.empty()); - - // Process the pending call. The queued calls should execute and the discovery - // session reference count should increase. - base::RunLoop().Run(); - EXPECT_EQ(3, callback_count_); - EXPECT_EQ(0, error_callback_count_); - EXPECT_EQ(1, observer.discovering_changed_count()); - EXPECT_TRUE(observer.last_discovering()); - EXPECT_TRUE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)3, discovery_sessions_.size()); - - // Verify the reference count by removing sessions 3 times. The last request - // should remain pending. - for (int i = 0; i < 3; i++) { - discovery_sessions_[i]->Stop(GetCallback(), GetErrorCallback()); - } - EXPECT_EQ(5, callback_count_); - EXPECT_EQ(0, error_callback_count_); - EXPECT_EQ(2, observer.discovering_changed_count()); - EXPECT_FALSE(observer.last_discovering()); - EXPECT_FALSE(adapter_->IsDiscovering()); - EXPECT_FALSE(discovery_sessions_[0]->IsActive()); - EXPECT_FALSE(discovery_sessions_[1]->IsActive()); - EXPECT_TRUE(discovery_sessions_[2]->IsActive()); - - // Request to stop the session whose call is pending should fail. - discovery_sessions_[2]->Stop(GetCallback(), GetErrorCallback()); - EXPECT_EQ(5, callback_count_); - EXPECT_EQ(1, error_callback_count_); - EXPECT_EQ(2, observer.discovering_changed_count()); - EXPECT_FALSE(observer.last_discovering()); - EXPECT_FALSE(adapter_->IsDiscovering()); - EXPECT_TRUE(discovery_sessions_[2]->IsActive()); - - // Request to start should get queued. - adapter_->StartDiscoverySession( - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - GetErrorCallback()); - EXPECT_EQ(5, callback_count_); - EXPECT_EQ(1, error_callback_count_); - EXPECT_EQ(2, observer.discovering_changed_count()); - EXPECT_FALSE(observer.last_discovering()); - EXPECT_FALSE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)3, discovery_sessions_.size()); - - // Run the pending request. - base::RunLoop().Run(); - EXPECT_EQ(6, callback_count_); - EXPECT_EQ(1, error_callback_count_); - EXPECT_EQ(3, observer.discovering_changed_count()); - EXPECT_TRUE(observer.last_discovering()); - EXPECT_TRUE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)3, discovery_sessions_.size()); - EXPECT_FALSE(discovery_sessions_[2]->IsActive()); - - // The queued request to start discovery should have been issued but is still - // pending. Run the loop and verify. - base::RunLoop().Run(); - EXPECT_EQ(7, callback_count_); - EXPECT_EQ(1, error_callback_count_); - EXPECT_EQ(3, observer.discovering_changed_count()); - EXPECT_TRUE(observer.last_discovering()); - EXPECT_TRUE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)4, discovery_sessions_.size()); - EXPECT_TRUE(discovery_sessions_[3]->IsActive()); -} - TEST_F(BluetoothBlueZTest, StartDiscoverySession) { GetAdapter(); @@ -1503,277 +1387,6 @@ EXPECT_EQ(nullptr, filter); } -// This test queues two requests to StartDiscovery with pre set filter. This -// should result in SetDiscoveryFilter, then StartDiscovery, and SetDiscovery -// DBus calls -TEST_F(BluetoothBlueZTest, QueuedSetDiscoveryFilterBeforeStartDiscovery) { - // Test a simulated discovery session. - fake_bluetooth_device_client_->SetSimulationIntervalMs(10); - GetAdapter(); - - TestBluetoothAdapterObserver observer(adapter_); - - BluetoothDiscoveryFilter* df = - new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE); - df->SetRSSI(-60); - df->AddUUID(BluetoothUUID("1000")); - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df); - - BluetoothDiscoveryFilter* df2 = - new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_CLASSIC); - df2->SetRSSI(-65); - df2->AddUUID(BluetoothUUID("1002")); - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); - - adapter_->SetPowered( - true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - callback_count_ = 0; - - // Queue two requests to start discovery session with filter. - adapter_->StartDiscoverySessionWithFilter( - std::move(discovery_filter), - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - adapter_->StartDiscoverySessionWithFilter( - std::move(discovery_filter2), - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - // Run requests, on DBus level there should be call SetDiscoveryFilter, then - // StartDiscovery, then SetDiscoveryFilter again. - base::RunLoop().Run(); - base::RunLoop().Run(); - - EXPECT_EQ(2, callback_count_); - EXPECT_EQ(0, error_callback_count_); - callback_count_ = 0; - - ASSERT_TRUE(adapter_->IsPowered()); - ASSERT_TRUE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)2, discovery_sessions_.size()); - ASSERT_TRUE(discovery_sessions_[0]->IsActive()); - ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); - ASSERT_TRUE(discovery_sessions_[1]->IsActive()); - ASSERT_TRUE(df2->Equals(*discovery_sessions_[1]->GetDiscoveryFilter())); - - auto* filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_NE(nullptr, filter); - EXPECT_EQ("auto", *filter->transport); - EXPECT_EQ(-65, *filter->rssi); - EXPECT_EQ(nullptr, filter->pathloss.get()); - auto uuids = *filter->uuids; - EXPECT_TRUE(base::Contains(uuids, "1000")); - EXPECT_TRUE(base::Contains(uuids, "1002")); - - discovery_sessions_[0]->Stop( - base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - base::RunLoop().Run(); - - discovery_sessions_[1]->Stop( - base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - base::RunLoop().Run(); - - EXPECT_EQ(2, callback_count_); - EXPECT_EQ(0, error_callback_count_); - - ASSERT_TRUE(adapter_->IsPowered()); - ASSERT_FALSE(adapter_->IsDiscovering()); - ASSERT_FALSE(discovery_sessions_[0]->IsActive()); - ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), - (BluetoothDiscoveryFilter*)nullptr); - ASSERT_FALSE(discovery_sessions_[1]->IsActive()); - ASSERT_EQ(discovery_sessions_[1]->GetDiscoveryFilter(), - (BluetoothDiscoveryFilter*)nullptr); - - filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_EQ(nullptr, filter); -} - -// Call StartFilteredDiscovery twice (2nd time while 1st call is still pending). -// Make the first SetDiscoveryFilter fail and the second one succeed. It should -// end up with one active discovery session. -TEST_F(BluetoothBlueZTest, QueuedSetDiscoveryFilterBeforeStartDiscoveryFail) { - // Test a simulated discovery session. - fake_bluetooth_device_client_->SetSimulationIntervalMs(10); - GetAdapter(); - - TestBluetoothAdapterObserver observer(adapter_); - - BluetoothDiscoveryFilter* df = - new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE); - df->SetRSSI(-60); - df->AddUUID(BluetoothUUID("1000")); - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df); - - BluetoothDiscoveryFilter* df2 = - new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_CLASSIC); - df2->SetRSSI(-65); - df2->AddUUID(BluetoothUUID("1002")); - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter2(df2); - - adapter_->SetPowered( - true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - callback_count_ = 0; - - fake_bluetooth_adapter_client_->MakeSetDiscoveryFilterFail(); - - // Queue two requests to start discovery session with filter. - adapter_->StartDiscoverySessionWithFilter( - std::move(discovery_filter), - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - adapter_->StartDiscoverySessionWithFilter( - std::move(discovery_filter2), - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - base::RunLoop().Run(); - - // First request to SetDiscoveryFilter should fail, resulting in no session - // being created. - EXPECT_EQ(0, callback_count_); - EXPECT_EQ(1, error_callback_count_); - error_callback_count_ = 0; - - ASSERT_TRUE(adapter_->IsPowered()); - ASSERT_FALSE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)0, discovery_sessions_.size()); - - base::RunLoop().Run(); - - // Second request should succeed - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - callback_count_ = 0; - - ASSERT_TRUE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)1, discovery_sessions_.size()); - ASSERT_TRUE(discovery_sessions_[0]->IsActive()); - ASSERT_TRUE(df2->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); - - auto* filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_NE(nullptr, filter); - EXPECT_EQ("bredr", *filter->transport); - EXPECT_EQ(-65, *filter->rssi); - EXPECT_EQ(nullptr, filter->pathloss.get()); - auto uuids = *filter->uuids; - EXPECT_TRUE(base::Contains(uuids, "1002")); - - discovery_sessions_[0]->Stop( - base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - base::RunLoop().Run(); - - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - - ASSERT_TRUE(adapter_->IsPowered()); - ASSERT_FALSE(adapter_->IsDiscovering()); - ASSERT_FALSE(discovery_sessions_[0]->IsActive()); - ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), - (BluetoothDiscoveryFilter*)nullptr); - - filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_EQ(nullptr, filter); -} - -TEST_F(BluetoothBlueZTest, SetDiscoveryFilterAfterStartDiscovery) { - // Test a simulated discovery session. - fake_bluetooth_device_client_->SetSimulationIntervalMs(10); - GetAdapter(); - - TestBluetoothAdapterObserver observer(adapter_); - - adapter_->SetPowered( - true, base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - adapter_->StartDiscoverySession( - base::Bind(&BluetoothBlueZTest::DiscoverySessionCallback, - base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - base::RunLoop().Run(); - EXPECT_EQ(2, callback_count_); - EXPECT_EQ(0, error_callback_count_); - callback_count_ = 0; - - ASSERT_TRUE(adapter_->IsPowered()); - ASSERT_TRUE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)1, discovery_sessions_.size()); - ASSERT_TRUE(discovery_sessions_[0]->IsActive()); - EXPECT_EQ(1, observer.discovering_changed_count()); - observer.Reset(); - - auto null_instance = std::unique_ptr<BluetoothDiscoveryFilter>(); - null_instance.reset(); - ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), null_instance.get()); - - auto* filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_EQ(nullptr, filter); - - BluetoothDiscoveryFilter* df = - new BluetoothDiscoveryFilter(device::BLUETOOTH_TRANSPORT_LE); - df->SetRSSI(-60); - df->AddUUID(BluetoothUUID("1000")); - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter(df); - - discovery_sessions_[0]->SetDiscoveryFilter( - std::move(discovery_filter), - base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - base::RunLoop().Run(); - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - callback_count_ = 0; - - ASSERT_TRUE(df->Equals(*discovery_sessions_[0]->GetDiscoveryFilter())); - - filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_NE(nullptr, filter); - EXPECT_EQ("le", *filter->transport); - EXPECT_EQ(-60, *filter->rssi); - EXPECT_EQ(nullptr, filter->pathloss.get()); - std::vector<std::string> uuids = *filter->uuids; - EXPECT_TRUE(base::Contains(uuids, "1000")); - - discovery_sessions_[0]->Stop( - base::Bind(&BluetoothBlueZTest::Callback, base::Unretained(this)), - base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - - base::RunLoop().Run(); - - EXPECT_EQ(1, callback_count_); - EXPECT_EQ(0, error_callback_count_); - - ASSERT_TRUE(adapter_->IsPowered()); - ASSERT_FALSE(adapter_->IsDiscovering()); - ASSERT_EQ((size_t)1, discovery_sessions_.size()); - ASSERT_FALSE(discovery_sessions_[0]->IsActive()); - ASSERT_EQ(discovery_sessions_[0]->GetDiscoveryFilter(), - (BluetoothDiscoveryFilter*)nullptr); - - filter = fake_bluetooth_adapter_client_->GetDiscoveryFilter(); - EXPECT_EQ(nullptr, filter); -} - // This unit test asserts that the basic reference counting, and filter merging // works correctly for discovery requests done via the BluetoothAdapter. TEST_F(BluetoothBlueZTest, SetDiscoveryFilterBeforeStartDiscoveryMultiple) { @@ -1943,7 +1556,6 @@ base::Unretained(this)), base::Bind(&BluetoothBlueZTest::ErrorCallback, base::Unretained(this))); - // each result in 1 requests. base::RunLoop().Run(); if (i == 0) { @@ -4429,7 +4041,6 @@ // Validate post shutdown state by calling all BluetoothAdapterBlueZ // members, in declaration order: - adapter_->Shutdown(); // DeleteOnCorrectThread omitted as we don't want to delete in this test. { TestBluetoothAdapterObserver observer(adapter_); // Calls AddObserver @@ -4518,7 +4129,6 @@ // GetPairing will DCHECK after Shutdown(). // SetAdapter will DCHECK after Shutdown(). // SetDefaultAdapterName will DCHECK after Shutdown(). - // RemoveAdapter will DCHECK after Shutdown(). adapter_bluez->NotifyAdapterPoweredChanged(false); adapter_bluez->DiscoverableChanged(false); adapter_bluez->DiscoveringChanged(false); @@ -4540,11 +4150,6 @@ EXPECT_EQ(0, callback_count_) << "AddDiscoverySession error"; EXPECT_EQ(1, error_callback_count_--) << "AddDiscoverySession error"; - adapter_bluez->RemoveDiscoverySession(nullptr, GetCallback(), - GetDiscoveryErrorCallback()); - EXPECT_EQ(0, callback_count_) << "RemoveDiscoverySession error"; - EXPECT_EQ(1, error_callback_count_--) << "RemoveDiscoverySession error"; - // OnStartDiscovery tested in Shutdown_OnStartDiscovery // OnStartDiscoveryError tested in Shutdown_OnStartDiscoveryError // OnStopDiscovery tested in Shutdown_OnStopDiscovery @@ -4579,8 +4184,6 @@ EXPECT_EQ(0, callback_count_) << "OnRegisterProfileError error"; EXPECT_EQ(0, error_callback_count_) << "OnRegisterProfileError error"; - adapter_bluez->ProcessQueuedDiscoveryRequests(); - // From BluetoothAdapater: adapter_->StartDiscoverySession( @@ -4614,7 +4217,7 @@ GetErrorCallback()); } adapter_->Shutdown(); - adapter_bluez->OnStartDiscovery(GetCallback(), GetDiscoveryErrorCallback()); + base::RunLoop().Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_); @@ -4634,8 +4237,7 @@ GetErrorCallback()); } adapter_->Shutdown(); - adapter_bluez->OnStartDiscoveryError(GetCallback(), - GetDiscoveryErrorCallback(), "", ""); + base::RunLoop().Run(); EXPECT_EQ(0, callback_count_); EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_); @@ -4654,9 +4256,8 @@ base::BindRepeating(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); - adapter_bluez->OnStartDiscovery(GetCallback(), GetDiscoveryErrorCallback()); - adapter_bluez->RemoveDiscoverySession(nullptr, GetCallback(), - GetDiscoveryErrorCallback()); + base::RunLoop().Run(); + discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); callback_count_ = 0; error_callback_count_ = 0; // Can now queue discovery sessions while waiting for OnStopDiscovery. @@ -4667,7 +4268,7 @@ GetErrorCallback()); } adapter_->Shutdown(); - adapter_bluez->OnStopDiscovery(GetCallback()); + base::RunLoop().Run(); // 1 successful stopped discovery from RemoveDiscoverySession, and // kNumberOfDiscoverySessions errors from AddDiscoverySession/OnStopDiscovery. @@ -4688,9 +4289,8 @@ base::BindRepeating(&BluetoothBlueZTest::DiscoverySessionCallback, base::Unretained(this)), GetErrorCallback()); - adapter_bluez->OnStartDiscovery(GetCallback(), GetDiscoveryErrorCallback()); - adapter_bluez->RemoveDiscoverySession(nullptr, GetCallback(), - GetDiscoveryErrorCallback()); + base::RunLoop().Run(); + discovery_sessions_[0]->Stop(GetCallback(), GetErrorCallback()); callback_count_ = 0; error_callback_count_ = 0; // Can now queue discovery sessions while waiting for OnStopDiscoveryError. @@ -4701,12 +4301,13 @@ GetErrorCallback()); } adapter_->Shutdown(); - adapter_bluez->OnStopDiscoveryError(GetDiscoveryErrorCallback(), "", ""); + base::RunLoop().Run(); - // 1 error reported to RemoveDiscoverySession because of OnStopDiscoveryError, - // and kNumberOfDiscoverySessions errors queued with AddDiscoverySession. - EXPECT_EQ(0, callback_count_); - EXPECT_EQ(1 + kNumberOfDiscoverySessions, error_callback_count_); + // kNumberOfDiscoverySessions reported errors because of the shutdown while + // starting. However, the stop call succeeded because the adapter shutdown + // and is therefore not discovering(also stop always returns success). + EXPECT_EQ(1, callback_count_); + EXPECT_EQ(kNumberOfDiscoverySessions, error_callback_count_); } TEST_F(BluetoothBlueZTest, ManufacturerDataChanged) {
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast.cc b/device/bluetooth/cast/bluetooth_adapter_cast.cc index 191ab21..343ee9ff 100644 --- a/device/bluetooth/cast/bluetooth_adapter_cast.cc +++ b/device/bluetooth/cast/bluetooth_adapter_cast.cc
@@ -234,48 +234,11 @@ UMABluetoothDiscoverySessionOutcome::SUCCESS); } -void BluetoothAdapterCast::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - // The discovery filter is unused for now, as the Cast bluetooth stack does - // not expose scan filters yet. However, implementation of filtering would - // save numerous UI<->IO threadhops by eliminating uneccessary calls to - // GetDevice(). - // TODO(b/77663782): Wire this up once scan filters are implemented. - (void)discovery_filter; - - // If there are pending requests, run the error call immediately. - if (pending_discovery_requests_.size() > 0u) { - std::move(error_callback) - .Run(UMABluetoothDiscoverySessionOutcome::REMOVE_WITH_PENDING_REQUEST); - return; - } - - // If the count is greater than 1, decrement the count and return success. - if (num_discovery_sessions_ > 1) { - num_discovery_sessions_--; - callback.Run(); - return; - } - - // This was the last active discovery session. Disable scanning. - num_discovery_sessions_--; +void BluetoothAdapterCast::StopScan(DiscoverySessionResultCallback callback) { DCHECK(scan_handle_); scan_handle_.reset(); - callback.Run(); -} - -void BluetoothAdapterCast::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - // The discovery filter is unused for now, as the Cast bluetooth stack does - // not expose scan filters yet. However, implementation of filtering would - // save numerous UI<->IO threadhops by eliminating unnecessary calls to - // GetDevice(). - NOTIMPLEMENTED(); - callback.Run(); + std::move(callback).Run(/*is_error*/ false, + UMABluetoothDiscoverySessionOutcome::SUCCESS); } void BluetoothAdapterCast::RemovePairingDelegateInternal(
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast.h b/device/bluetooth/cast/bluetooth_adapter_cast.h index 80c571b..7be88e9 100644 --- a/device/bluetooth/cast/bluetooth_adapter_cast.h +++ b/device/bluetooth/cast/bluetooth_adapter_cast.h
@@ -96,14 +96,7 @@ void UpdateFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; void RemovePairingDelegateInternal( BluetoothDevice::PairingDelegate* pairing_delegate) override;
diff --git a/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc b/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc index affde95..7802a72 100644 --- a/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc +++ b/device/bluetooth/cast/bluetooth_adapter_cast_unittest.cc
@@ -17,7 +17,7 @@ BluetoothAdapterCastTest() = default; ~BluetoothAdapterCastTest() override { BluetoothAdapterCast::ResetFactoryForTest(); - }; + } private: base::test::ScopedTaskEnvironment scoped_task_environment_;
diff --git a/device/bluetooth/dbus/bluetooth_adapter_client.cc b/device/bluetooth/dbus/bluetooth_adapter_client.cc index dc694f3e..7c7b29c2 100644 --- a/device/bluetooth/dbus/bluetooth_adapter_client.cc +++ b/device/bluetooth/dbus/bluetooth_adapter_client.cc
@@ -25,6 +25,9 @@ namespace bluez { +// Automatically determine transport mode. +constexpr char kBluezAutoTransport[] = "auto"; + namespace { // TODO(rkc) Find better way to do this. @@ -143,7 +146,7 @@ if (filter.transport.get()) transport.reset(new std::string(*filter.transport)); else - transport.reset(); + transport.reset(new std::string(kBluezAutoTransport)); if (filter.uuids.get()) uuids.reset(new std::vector<std::string>(*filter.uuids));
diff --git a/device/bluetooth/test/fake_central.cc b/device/bluetooth/test/fake_central.cc index f9973ec..2d13a2e 100644 --- a/device/bluetooth/test/fake_central.cc +++ b/device/bluetooth/test/fake_central.cc
@@ -553,7 +553,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce( - std::move(callback), /*is_error*/ true, + std::move(callback), /*is_error=*/true, device::UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT)); return; } @@ -571,7 +571,7 @@ base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce( - std::move(callback), /*is_error*/ true, + std::move(callback), /*is_error=*/true, device::UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT)); return; } @@ -582,36 +582,21 @@ device::UMABluetoothDiscoverySessionOutcome::SUCCESS)); } -void FakeCentral::RemoveDiscoverySession( - device::BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { +void FakeCentral::StopScan(DiscoverySessionResultCallback callback) { if (!IsPresent()) { base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce( - std::move(error_callback), + std::move(callback), /*is_error=*/false, device::UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT)); return; } - if (NumDiscoverySessions() == 1) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::BindOnce(std::move(error_callback), - device::UMABluetoothDiscoverySessionOutcome::UNKNOWN)); - return; - } - - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, - base::BindOnce(callback)); -} - -void FakeCentral::SetDiscoveryFilter( - std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - NOTREACHED(); + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce( + std::move(callback), /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::ADAPTER_NOT_PRESENT)); } void FakeCentral::RemovePairingDelegateInternal(
diff --git a/device/bluetooth/test/fake_central.h b/device/bluetooth/test/fake_central.h index 13a24e6..176f36a 100644 --- a/device/bluetooth/test/fake_central.h +++ b/device/bluetooth/test/fake_central.h
@@ -187,14 +187,7 @@ void StartScanWithFilter( std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - device::BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; + void StopScan(DiscoverySessionResultCallback callback) override; void RemovePairingDelegateInternal( device::BluetoothDevice::PairingDelegate* pairing_delegate) override;
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.cc b/device/bluetooth/test/mock_bluetooth_adapter.cc index 2f690e5..fe66aca 100644 --- a/device/bluetooth/test/mock_bluetooth_adapter.cc +++ b/device/bluetooth/test/mock_bluetooth_adapter.cc
@@ -56,25 +56,7 @@ void MockBluetoothAdapter::UpdateFilter( std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) { - StartScanWithFilter_(discovery_filter.get(), callback); -} - -void MockBluetoothAdapter::RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - RemoveDiscoverySession_(discovery_filter, callback, error_callback); -} - -void MockBluetoothAdapter::SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) { - if (discovery_filter.get()) { - SetDiscoveryFilterRaw(discovery_filter.get(), callback, error_callback); - return; - } - SetDiscoveryFilterRaw(nullptr, callback, error_callback); + UpdateFilter_(discovery_filter.get(), callback); } void MockBluetoothAdapter::AddMockDevice(
diff --git a/device/bluetooth/test/mock_bluetooth_adapter.h b/device/bluetooth/test/mock_bluetooth_adapter.h index 5b9d836..a330c92 100644 --- a/device/bluetooth/test/mock_bluetooth_adapter.h +++ b/device/bluetooth/test/mock_bluetooth_adapter.h
@@ -75,13 +75,16 @@ MOCK_METHOD2( StartScanWithFilter_, void(const BluetoothDiscoveryFilter*, - base::OnceCallback<void(/*is_error*/ bool, + base::OnceCallback<void(/*is_error=*/bool, UMABluetoothDiscoverySessionOutcome)>& callback)); - MOCK_METHOD3(RemoveDiscoverySession_, - void(BluetoothDiscoveryFilter* discovery_filter, - const base::RepeatingClosure& callback, - DiscoverySessionErrorCallback& error_callback)); + MOCK_METHOD2( + UpdateFilter_, + void(const BluetoothDiscoveryFilter*, + base::OnceCallback<void(/*is_error=*/bool, + UMABluetoothDiscoverySessionOutcome)>& + callback)); + MOCK_METHOD1(StopScan, void(DiscoverySessionResultCallback callback)); MOCK_METHOD3(SetDiscoveryFilterRaw, void(const BluetoothDiscoveryFilter*, const base::RepeatingClosure& callback, @@ -135,14 +138,6 @@ DiscoverySessionResultCallback callback) override; void UpdateFilter(std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, DiscoverySessionResultCallback callback) override; - void RemoveDiscoverySession( - BluetoothDiscoveryFilter* discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; - void SetDiscoveryFilter( - std::unique_ptr<BluetoothDiscoveryFilter> discovery_filter, - const base::Closure& callback, - DiscoverySessionErrorCallback error_callback) override; void RegisterAdvertisement( std::unique_ptr<BluetoothAdvertisement::Data> advertisement_data, const CreateAdvertisementCallback& callback,
diff --git a/device/fido/ble/fido_ble_discovery_unittest.cc b/device/fido/ble/fido_ble_discovery_unittest.cc index 8539506..676d8e8 100644 --- a/device/fido/ble/fido_ble_discovery_unittest.cc +++ b/device/fido/ble/fido_ble_discovery_unittest.cc
@@ -126,9 +126,9 @@ base::test::ScopedTaskEnvironment::TimeSource::MOCK_TIME}; private: - FidoBleDiscovery discovery_; - MockFidoDiscoveryObserver observer_; scoped_refptr<MockBluetoothAdapter> adapter_; + MockFidoDiscoveryObserver observer_; + FidoBleDiscovery discovery_; }; TEST_F(FidoBleDiscoveryTest, @@ -147,8 +147,17 @@ EXPECT_CALL(*adapter(), IsPowered()).WillOnce(Return(false)); // After BluetoothAdapter is powered on, we expect that discovery session - // starts again. - EXPECT_CALL(*adapter(), StartScanWithFilter_); + // starts again. Immediately calling the callback so that it does not hold a + // reference to the adapter. + EXPECT_CALL(*adapter(), StartScanWithFilter_) + .WillOnce(testing::Invoke( + [](const device::BluetoothDiscoveryFilter* discovery_filter, + device::BluetoothAdapter::DiscoverySessionResultCallback& + callback) { + std::move(callback).Run( + /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + })); discovery()->Start(); scoped_task_environment_.FastForwardUntilNoTasksRemain(); adapter()->NotifyAdapterPoweredChanged(true);
diff --git a/extensions/browser/api/bluetooth/bluetooth_apitest.cc b/extensions/browser/api/bluetooth/bluetooth_apitest.cc index 656ae18..98c65dc 100644 --- a/extensions/browser/api/bluetooth/bluetooth_apitest.cc +++ b/extensions/browser/api/bluetooth/bluetooth_apitest.cc
@@ -87,18 +87,18 @@ false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS); } - void RemoveDiscoverySessionOverride( - device::BluetoothDiscoveryFilter* discovery_filter, - const base::RepeatingClosure& callback, - base::OnceCallback<void(device::UMABluetoothDiscoverySessionOutcome)>& - error_callback) { + void StopScanOverride( + device::BluetoothAdapter::DiscoverySessionResultCallback callback) { if (fail_next_call_) { - std::move(error_callback) - .Run(device::UMABluetoothDiscoverySessionOutcome::UNKNOWN); + std::move(callback).Run( + /*is_error=*/true, + device::UMABluetoothDiscoverySessionOutcome::UNKNOWN); fail_next_call_ = false; return; } - callback.Run(); + std::move(callback).Run( + /*is_error=*/false, + device::UMABluetoothDiscoverySessionOutcome::SUCCESS); } void FailNextCall() { fail_next_call_ = true; } @@ -196,7 +196,6 @@ utils::RunFunctionAndReturnError(start_function.get(), "[]", browser())); testing::Mock::VerifyAndClearExpectations(mock_adapter_); - // Simulate successful start discovery EXPECT_CALL(*mock_adapter_, StartScanWithFilter_(_, _)) .WillOnce(Invoke(this, &BluetoothApiTest::StartScanOverride)); @@ -205,23 +204,12 @@ extensions::api_test_utils::NONE); testing::Mock::VerifyAndClearExpectations(mock_adapter_); - // Simulate stop discovery with a failure - EXPECT_CALL(*mock_adapter_, RemoveDiscoverySession_(_, _, _)) - .WillOnce( - Invoke(this, &BluetoothApiTest::RemoveDiscoverySessionOverride)); + EXPECT_CALL(*mock_adapter_, StopScan(_)) + .WillOnce(Invoke(this, &BluetoothApiTest::StopScanOverride)); FailNextCall(); scoped_refptr<api::BluetoothStopDiscoveryFunction> stop_function; stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); - error = - utils::RunFunctionAndReturnError(stop_function.get(), "[]", browser()); - ASSERT_FALSE(error.empty()); - - // Simiulate successful stop discovery - EXPECT_CALL(*mock_adapter_, RemoveDiscoverySession_(_, _, _)) - .WillOnce( - Invoke(this, &BluetoothApiTest::RemoveDiscoverySessionOverride)); - stop_function = setupFunction(new api::BluetoothStopDiscoveryFunction); (void)utils::RunFunctionAndReturnSingleResult(stop_function.get(), "[]", browser()); SetUpMockAdapter(); @@ -230,9 +218,8 @@ IN_PROC_BROWSER_TEST_F(BluetoothApiTest, DiscoveryCallback) { EXPECT_CALL(*mock_adapter_, StartScanWithFilter_(_, _)) .WillOnce(Invoke(this, &BluetoothApiTest::StartScanOverride)); - EXPECT_CALL(*mock_adapter_, RemoveDiscoverySession_(_, _, _)) - .WillOnce( - Invoke(this, &BluetoothApiTest::RemoveDiscoverySessionOverride)); + EXPECT_CALL(*mock_adapter_, StopScan(_)) + .WillOnce(Invoke(this, &BluetoothApiTest::StopScanOverride)); ResultCatcher catcher; catcher.RestrictToBrowserContext(browser()->profile()); @@ -278,9 +265,8 @@ EXPECT_CALL(*mock_adapter_, StartScanWithFilter_(_, _)) .WillOnce(Invoke(this, &BluetoothApiTest::StartScanOverride)); - EXPECT_CALL(*mock_adapter_, RemoveDiscoverySession_(_, _, _)) - .WillOnce( - Invoke(this, &BluetoothApiTest::RemoveDiscoverySessionOverride)); + EXPECT_CALL(*mock_adapter_, StopScan(_)) + .WillOnce(Invoke(this, &BluetoothApiTest::StopScanOverride)); ExtensionTestMessageListener discovery_started("ready", true); ASSERT_TRUE(LoadExtension(
diff --git a/extensions/browser/api/bluetooth/bluetooth_event_router.cc b/extensions/browser/api/bluetooth/bluetooth_event_router.cc index 88a8d998..88945ef1 100644 --- a/extensions/browser/api/bluetooth/bluetooth_event_router.cc +++ b/extensions/browser/api/bluetooth/bluetooth_event_router.cc
@@ -186,7 +186,13 @@ const base::Closure& callback, const base::Closure& error_callback) { BLUETOOTH_LOG(USER) << "SetDiscoveryFilter"; + if (!adapter_.get()) { + BLUETOOTH_LOG(ERROR) << "Unable to get Bluetooth adapter."; + error_callback.Run(); + return; + } if (adapter != adapter_.get()) { + BLUETOOTH_LOG(ERROR) << "Bluetooth adapter mismatch."; error_callback.Run(); return; } @@ -200,9 +206,14 @@ return; } - // extension is already running discovery, update it's discovery filter - iter->second->SetDiscoveryFilter(std::move(discovery_filter), callback, - error_callback); + // If the session has already started simply start a new one. The callback + // will automatically delete the old session and put the new session (with its + // new filter) in as this extension's session + adapter->StartDiscoverySessionWithFilter( + std::move(discovery_filter), + base::Bind(&BluetoothEventRouter::OnStartDiscoverySession, + weak_ptr_factory_.GetWeakPtr(), extension_id, callback), + error_callback); } BluetoothApiPairingDelegate* BluetoothEventRouter::GetPairingDelegate( @@ -249,6 +260,7 @@ LOG(ERROR) << "Unable to get adapter for extension_id: " << extension_id; return; } + if (base::Contains(pairing_delegate_map_, extension_id)) { // For WebUI there may be more than one page open to the same url // (e.g. chrome://settings). These will share the same pairing delegate.
diff --git a/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc b/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc index 5b61182..c7b265b 100644 --- a/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc +++ b/extensions/browser/api/bluetooth/bluetooth_event_router_unittest.cc
@@ -117,13 +117,18 @@ EXPECT_CALL( *mock_adapter_, StartScanWithFilter_(testing::Pointee(IsFilterEqual(&df)), testing::_)) - .Times(1); + .WillOnce(testing::Invoke( + [](const device::BluetoothDiscoveryFilter* filter, + base::OnceCallback<void( + /*is_error*/ bool, + device::UMABluetoothDiscoverySessionOutcome)>& callback) { + std::move(callback).Run( + false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + })); // RemoveDiscoverySession will be called when the BluetoothDiscoverySession // is destroyed - EXPECT_CALL(*mock_adapter_, - RemoveDiscoverySession_(testing::_, testing::_, testing::_)) - .Times(1); + EXPECT_CALL(*mock_adapter_, StopScan(testing::_)).Times(1); router_->StartDiscoverySession(mock_adapter_, kTestExtensionId, base::DoNothing(), base::DoNothing());
diff --git a/extensions/browser/api/bluetooth/bluetooth_private_apitest.cc b/extensions/browser/api/bluetooth/bluetooth_private_apitest.cc index 887aff7..0312f458 100644 --- a/extensions/browser/api/bluetooth/bluetooth_private_apitest.cc +++ b/extensions/browser/api/bluetooth/bluetooth_private_apitest.cc
@@ -131,7 +131,15 @@ } void StartScanOverride( - base::OnceCallback<void(/*is_error*/ bool, + base::OnceCallback<void(/*is_error=*/bool, + device::UMABluetoothDiscoverySessionOutcome)>& + callback) { + std::move(callback).Run( + false, device::UMABluetoothDiscoverySessionOutcome::SUCCESS); + } + + void UpdateFilterOverride( + base::OnceCallback<void(/*is_error=*/bool, device::UMABluetoothDiscoverySessionOutcome)>& callback) { std::move(callback).Run( @@ -247,6 +255,8 @@ #endif IN_PROC_BROWSER_TEST_F(BluetoothPrivateApiTest, DiscoveryFilter) { + BluetoothDiscoveryFilter discovery_filter_default( + device::BLUETOOTH_TRANSPORT_DUAL); BluetoothDiscoveryFilter discovery_filter(device::BLUETOOTH_TRANSPORT_LE); discovery_filter.SetPathloss(50); discovery_filter.AddUUID(BluetoothUUID("cafe")); @@ -258,9 +268,11 @@ .Times(1) .WillOnce(WithArgs<1>( Invoke(this, &BluetoothPrivateApiTest::StartScanOverride))); - EXPECT_CALL(*mock_adapter_, SetDiscoveryFilterRaw(Eq(nullptr), _, _)) + EXPECT_CALL(*mock_adapter_, + UpdateFilter_(IsFilterEqual(&discovery_filter_default), _)) .Times(1) - .WillOnce(InvokeCallbackArgument<1>()); + .WillOnce(WithArgs<1>( + Invoke(this, &BluetoothPrivateApiTest::UpdateFilterOverride))); ASSERT_TRUE(RunComponentExtensionTest("bluetooth_private/discovery_filter")) << message_; }
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h index 1330b4e..e6d91e98 100644 --- a/extensions/browser/extension_function_histogram_value.h +++ b/extensions/browser/extension_function_histogram_value.h
@@ -932,8 +932,8 @@ DELETED_FILESYSTEM_UNOBSERVEENTRY = 871, DELETED_FILESYSTEM_GETOBSERVEDENTRIES = 872, BROWSINGDATA_REMOVESERVICEWORKERS = 873, - USBPRIVATE_GETDEVICES = 874, - USBPRIVATE_GETDEVICEINFO = 875, + DELETED_USBPRIVATE_GETDEVICES = 874, + DELETED_USBPRIVATE_GETDEVICEINFO = 875, DELETED_EASYUNLOCKPRIVATE_UPDATESCREENLOCKSTATE = 876, CAST_CHANNEL_GETLOGS = 877, DELETED_EASYUNLOCKPRIVATE_SETPERMITACCESS = 878,
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index e20bb74c..88a5ad6 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -269,6 +269,12 @@ DCHECK_EQ(GaiaUrls::GetInstance()->gaia_url(), gaia_gurl.GetOrigin()) << gaia_gurl; resource_request->site_for_cookies = GaiaUrls::GetInstance()->gaia_url(); + url::Origin origin = + url::Origin::Create(GaiaUrls::GetInstance()->gaia_url()); + resource_request->trusted_params = + network::ResourceRequest::TrustedParams(); + resource_request->trusted_params->network_isolation_key = + net::NetworkIsolationKey(origin, origin); } if (!body.empty())
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 6dabf09..ee58eba 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg
@@ -3371,7 +3371,7 @@ mixins: "fyi-ci" } builders { - name: "Mac Goma Canary (clobber)" + name: "mac-archive-rel-goma-canary" dimensions: "os:Mac-10.13" dimensions: "cores:4" mixins: "fyi-ci" @@ -3388,13 +3388,13 @@ mixins: "builderless" } builders { - name: "Android Builder (dbg) Goma Canary" + name: "android-archive-dbg-goma-canary" mixins: "fyi-ci" mixins: "linux-xenial" mixins: "builderless" } builders { - name: "Mac Goma Canary LocalOutputCache" + name: "mac-archive-rel-goma-canary-localoutputcache" dimensions: "os:Mac-10.13" dimensions: "cores:4" mixins: "fyi-ci" @@ -3416,7 +3416,7 @@ mixins: "fyi-ci" } builders { - name: "Linux x64 Goma Canary LocalOutputCache" + name: "linux-archive-rel-goma-canary-localoutputcache" mixins: "fyi-ci" mixins: "builderless" mixins: "linux-xenial" @@ -3440,7 +3440,7 @@ mixins: "fyi-ci" } builders { - name: "Win Goma Canary LocalOutputCache" + name: "win32-archive-rel-goma-canary-localoutputcache" dimensions: "os:Windows-10" mixins: "fyi-ci" } @@ -3456,7 +3456,7 @@ mixins: "fyi-ci" } builders { - name: "Linux x64 Goma Canary (clobber)" + name: "linux-archive-rel-goma-canary" mixins: "fyi-ci" mixins: "linux-xenial" mixins: "builderless" @@ -3469,7 +3469,7 @@ mixins: "fyi-ci" } builders { - name: "Mac Goma Latest Client (clobber)" + name: "mac-archive-rel-goma-latest" dimensions: "os:Mac-10.13" dimensions: "cores:4" mixins: "fyi-ci" @@ -3480,12 +3480,13 @@ mixins: "fyi-ci" } builders { - name: "Android Builder (dbg) Goma Latest Client" + name: "android-archive-dbg-goma-latest" mixins: "linux-xenial" + mixins: "builderless" mixins: "fyi-ci" } builders { - name: "Mac Goma Latest Client LocalOutputCache" + name: "mac-archive-rel-goma-latest-localoutputcache" dimensions: "os:Mac-10.13" dimensions: "cores:4" mixins: "fyi-ci" @@ -3507,8 +3508,9 @@ mixins: "fyi-ci" } builders { - name: "Linux x64 Goma Latest Client LocalOutputCache" + name: "linux-archive-rel-goma-latest-localoutputcache" mixins: "linux-xenial" + mixins: "builderless" mixins: "fyi-ci" } builders { @@ -3527,7 +3529,7 @@ mixins: "fyi-ci" } builders { - name: "Win Goma Latest Client LocalOutputCache" + name: "win32-archive-rel-goma-latest-localoutputcache" dimensions: "os:Windows-10" mixins: "fyi-ci" } @@ -3543,8 +3545,9 @@ mixins: "fyi-ci" } builders { - name: "Linux x64 Goma Latest Client (clobber)" + name: "linux-archive-rel-goma-latest" mixins: "linux-xenial" + mixins: "builderless" mixins: "fyi-ci" } builders { @@ -3763,7 +3766,7 @@ name: "android-cronet-arm-dbg" } builders { - name: "android-kitkat-arm-coverage-dbg" + name: "android-kitkat-arm-coverage-rel" mixins: "android-try" mixins: "goma-j150" mixins: "builderless"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg index 2bf46ec..dee53a6 100644 --- a/infra/config/luci-milo.cfg +++ b/infra/config/luci-milo.cfg
@@ -1858,7 +1858,7 @@ category: "win|dbg" } builders { - name: "buildbucket/luci.chromium.ci/Win Goma Canary LocalOutputCache" + name: "buildbucket/luci.chromium.ci/win32-archive-rel-goma-canary-localoutputcache" category: "win|rel" short_name: "loc" } @@ -1888,7 +1888,7 @@ category: "mac|dbg" } builders { - name: "buildbucket/luci.chromium.ci/Mac Goma Canary (clobber)" + name: "buildbucket/luci.chromium.ci/mac-archive-rel-goma-canary" category: "mac|rel" short_name: "clb" } @@ -1898,7 +1898,7 @@ short_name: "clb" } builders { - name: "buildbucket/luci.chromium.ci/Mac Goma Canary LocalOutputCache" + name: "buildbucket/luci.chromium.ci/mac-archive-rel-goma-canary-localoutputcache" category: "mac|rel" short_name: "loc" } @@ -1911,17 +1911,17 @@ category: "linux|rel" } builders { - name: "buildbucket/luci.chromium.ci/Linux x64 Goma Canary (clobber)" + name: "buildbucket/luci.chromium.ci/linux-archive-rel-goma-canary" category: "linux|rel" short_name: "clb" } builders { - name: "buildbucket/luci.chromium.ci/Linux x64 Goma Canary LocalOutputCache" + name: "buildbucket/luci.chromium.ci/linux-archive-rel-goma-canary-localoutputcache" category: "linux|rel" short_name: "loc" } builders { - name: "buildbucket/luci.chromium.ci/Android Builder (dbg) Goma Canary" + name: "buildbucket/luci.chromium.ci/android-archive-dbg-goma-canary" category: "android|dbg" } builders { @@ -1977,7 +1977,7 @@ category: "mac|dbg" } builders { - name: "buildbucket/luci.chromium.ci/Mac Goma Latest Client (clobber)" + name: "buildbucket/luci.chromium.ci/mac-archive-rel-goma-latest" category: "mac|rel" short_name: "clb" } @@ -1987,7 +1987,7 @@ short_name: "clb" } builders { - name: "buildbucket/luci.chromium.ci/Mac Goma Latest Client LocalOutputCache" + name: "buildbucket/luci.chromium.ci/mac-archive-rel-goma-latest-localoutputcache" category: "mac|rel" short_name: "loc" } @@ -2000,17 +2000,17 @@ category: "linux|rel" } builders { - name: "buildbucket/luci.chromium.ci/Linux x64 Goma Latest Client (clobber)" + name: "buildbucket/luci.chromium.ci/linux-archive-rel-goma-latest" category: "linux|rel" short_name: "clb" } builders { - name: "buildbucket/luci.chromium.ci/Linux x64 Goma Latest Client LocalOutputCache" + name: "buildbucket/luci.chromium.ci/linux-archive-rel-goma-latest-localoutputcache" category: "linux|rel" short_name: "loc" } builders { - name: "buildbucket/luci.chromium.ci/Android Builder (dbg) Goma Latest Client" + name: "buildbucket/luci.chromium.ci/android-archive-dbg-goma-latest" category: "android|dbg" } builders { @@ -2126,12 +2126,12 @@ category: "goma|linux" } builders { - name: "buildbucket/luci.chromium.ci/Linux x64 Goma Canary (clobber)" + name: "buildbucket/luci.chromium.ci/linux-archive-rel-goma-canary" category: "goma|linux" short_name: "clb" } builders { - name: "buildbucket/luci.chromium.ci/Linux x64 Goma Canary LocalOutputCache" + name: "buildbucket/luci.chromium.ci/linux-archive-rel-goma-canary-localoutputcache" category: "goma|linux" short_name: "loc" } @@ -2149,12 +2149,12 @@ category: "goma|mac" } builders { - name: "buildbucket/luci.chromium.ci/Mac Goma Canary (clobber)" + name: "buildbucket/luci.chromium.ci/mac-archive-rel-goma-canary" category: "goma|mac" short_name: "clb" } builders { - name: "buildbucket/luci.chromium.ci/Mac Goma Canary LocalOutputCache" + name: "buildbucket/luci.chromium.ci/mac-archive-rel-goma-canary-localoutputcache" category: "goma|mac" short_name: "loc" } @@ -2172,7 +2172,7 @@ category: "goma|win" } builders { - name: "buildbucket/luci.chromium.ci/Win Goma Canary LocalOutputCache" + name: "buildbucket/luci.chromium.ci/win32-archive-rel-goma-canary-localoutputcache" category: "goma|win" short_name: "loc" } @@ -4773,7 +4773,7 @@ name: "buildbucket/luci.chromium.try/android-cronet-arm-dbg" } builders { - name: "buildbucket/luci.chromium.try/android-kitkat-arm-coverage-dbg" + name: "buildbucket/luci.chromium.try/android-kitkat-arm-coverage-rel" } builders { name: "buildbucket/luci.chromium.try/android-kitkat-arm-rel"
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg index f3ff451..6a7dcf13 100644 --- a/infra/config/luci-scheduler.cfg +++ b/infra/config/luci-scheduler.cfg
@@ -69,8 +69,8 @@ triggers: "ASan Release Media (32-bit x86 with V8-ARM)" triggers: "Afl Upload Linux ASan" triggers: "Android ASAN (dbg)" - triggers: "Android Builder (dbg) Goma Canary" - triggers: "Android Builder (dbg) Goma Latest Client" + triggers: "android-archive-dbg-goma-canary" + triggers: "android-archive-dbg-goma-latest" triggers: "Android CFI" triggers: "Android FYI 32 Vk Release (Pixel 2)" triggers: "Android FYI 32 dEQP Vk Release (Pixel 2)" @@ -206,10 +206,10 @@ triggers: "Linux TSan Builder" triggers: "Linux Viz" triggers: "Linux remote_run Builder" - triggers: "Linux x64 Goma Canary (clobber)" - triggers: "Linux x64 Goma Canary LocalOutputCache" - triggers: "Linux x64 Goma Latest Client (clobber)" - triggers: "Linux x64 Goma Latest Client LocalOutputCache" + triggers: "linux-archive-rel-goma-canary" + triggers: "linux-archive-rel-goma-canary-localoutputcache" + triggers: "linux-archive-rel-goma-latest" + triggers: "linux-archive-rel-goma-latest-localoutputcache" triggers: "MSAN Release (chained origins)" triggers: "MSAN Release (no origins)" triggers: "Mac ASAN Release Media" @@ -224,10 +224,10 @@ triggers: "Mac Builder Goma Latest Client" triggers: "Mac Builder" triggers: "Mac FYI GPU ASAN Release" - triggers: "Mac Goma Canary (clobber)" - triggers: "Mac Goma Canary LocalOutputCache" - triggers: "Mac Goma Latest Client (clobber)" - triggers: "Mac Goma Latest Client LocalOutputCache" + triggers: "mac-archive-rel-goma-canary" + triggers: "mac-archive-rel-goma-canary-localoutputcache" + triggers: "mac-archive-rel-goma-latest" + triggers: "mac-archive-rel-goma-latest-localoutputcache" triggers: "Mac deterministic (dbg)" triggers: "Mac deterministic" triggers: "Memory Infra Tester" @@ -285,8 +285,8 @@ triggers: "Win Builder Goma Canary" triggers: "Win Builder Goma Latest Client" triggers: "Win Builder" - triggers: "Win Goma Canary LocalOutputCache" - triggers: "Win Goma Latest Client LocalOutputCache" + triggers: "win32-archive-rel-goma-canary-localoutputcache" + triggers: "win32-archive-rel-goma-latest-localoutputcache" triggers: "Win cl.exe Goma Canary LocalOutputCache" triggers: "Win cl.exe Goma Latest Client LocalOutputCache" triggers: "Win x64 Builder (dbg)" @@ -3381,22 +3381,22 @@ } job { - id: "Android Builder (dbg) Goma Canary" + id: "android-archive-dbg-goma-canary" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Android Builder (dbg) Goma Canary" + builder: "android-archive-dbg-goma-canary" } } job { - id: "Android Builder (dbg) Goma Latest Client" + id: "android-archive-dbg-goma-latest" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Android Builder (dbg) Goma Latest Client" + builder: "android-archive-dbg-goma-latest" } } @@ -3784,42 +3784,42 @@ } job { - id: "Linux x64 Goma Canary (clobber)" + id: "linux-archive-rel-goma-canary" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Linux x64 Goma Canary (clobber)" + builder: "linux-archive-rel-goma-canary" } } job { - id: "Linux x64 Goma Canary LocalOutputCache" + id: "linux-archive-rel-goma-canary-localoutputcache" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Linux x64 Goma Canary LocalOutputCache" + builder: "linux-archive-rel-goma-canary-localoutputcache" } } job { - id: "Linux x64 Goma Latest Client (clobber)" + id: "linux-archive-rel-goma-latest" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Linux x64 Goma Latest Client (clobber)" + builder: "linux-archive-rel-goma-latest" } } job { - id: "Linux x64 Goma Latest Client LocalOutputCache" + id: "linux-archive-rel-goma-latest-localoutputcache" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Linux x64 Goma Latest Client LocalOutputCache" + builder: "linux-archive-rel-goma-latest-localoutputcache" } } @@ -3970,22 +3970,22 @@ } job { - id: "Mac Goma Canary (clobber)" + id: "mac-archive-rel-goma-canary" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Mac Goma Canary (clobber)" + builder: "mac-archive-rel-goma-canary" } } job { - id: "Mac Goma Canary LocalOutputCache" + id: "mac-archive-rel-goma-canary-localoutputcache" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Mac Goma Canary LocalOutputCache" + builder: "mac-archive-rel-goma-canary-localoutputcache" } } @@ -4000,22 +4000,22 @@ } job { - id: "Mac Goma Latest Client (clobber)" + id: "mac-archive-rel-goma-latest" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Mac Goma Latest Client (clobber)" + builder: "mac-archive-rel-goma-latest" } } job { - id: "Mac Goma Latest Client LocalOutputCache" + id: "mac-archive-rel-goma-latest-localoutputcache" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Mac Goma Latest Client LocalOutputCache" + builder: "mac-archive-rel-goma-latest-localoutputcache" } } @@ -4310,12 +4310,12 @@ } job { - id: "Win Goma Canary LocalOutputCache" + id: "win32-archive-rel-goma-canary-localoutputcache" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Win Goma Canary LocalOutputCache" + builder: "win32-archive-rel-goma-canary-localoutputcache" } } @@ -4350,12 +4350,12 @@ } job { - id: "Win Goma Latest Client LocalOutputCache" + id: "win32-archive-rel-goma-latest-localoutputcache" acl_sets: "default" buildbucket: { server: "cr-buildbucket.appspot.com" bucket: "luci.chromium.ci" - builder: "Win Goma Latest Client LocalOutputCache" + builder: "win32-archive-rel-goma-latest-localoutputcache" } }
diff --git a/ios/chrome/app/startup_tasks.mm b/ios/chrome/app/startup_tasks.mm index ade03257..e5a5b73 100644 --- a/ios/chrome/app/startup_tasks.mm +++ b/ios/chrome/app/startup_tasks.mm
@@ -83,17 +83,14 @@ } - (void)donateIntents { - if (@available(iOS 12.0, *)) { - SearchInChromeIntent* searchInChromeIntent = - [[SearchInChromeIntent alloc] init]; - searchInChromeIntent.suggestedInvocationPhrase = l10n_util::GetNSString( - IDS_IOS_INTENTS_SEARCH_IN_CHROME_INVOCATION_PHRASE); - INInteraction* interaction = - [[INInteraction alloc] initWithIntent:searchInChromeIntent - response:nil]; - [interaction donateInteractionWithCompletion:^(NSError* _Nullable error){ - }]; - } + SearchInChromeIntent* searchInChromeIntent = + [[SearchInChromeIntent alloc] init]; + searchInChromeIntent.suggestedInvocationPhrase = l10n_util::GetNSString( + IDS_IOS_INTENTS_SEARCH_IN_CHROME_INVOCATION_PHRASE); + INInteraction* interaction = + [[INInteraction alloc] initWithIntent:searchInChromeIntent response:nil]; + [interaction donateInteractionWithCompletion:^(NSError* _Nullable error){ + }]; } #pragma mark - Private methods.
diff --git a/ios/chrome/browser/download/BUILD.gn b/ios/chrome/browser/download/BUILD.gn index 023419d..6886e05f 100644 --- a/ios/chrome/browser/download/BUILD.gn +++ b/ios/chrome/browser/download/BUILD.gn
@@ -29,7 +29,6 @@ ] deps = [ - ":features", "//base", "//components/keyed_service/core", "//components/keyed_service/ios", @@ -49,19 +48,6 @@ configs += [ "//build/config/compiler:enable_arc" ] } -source_set("features") { - sources = [ - "features.h", - "features.mm", - ] - - deps = [ - "//base", - ] - - configs += [ "//build/config/compiler:enable_arc" ] -} - source_set("mime_types") { sources = [ "pass_kit_mime_type.cc", @@ -94,7 +80,6 @@ "//base/test:test_support", "//ios/chrome/browser/browser_state:test_support", "//ios/chrome/browser/download", - "//ios/chrome/browser/download:features", "//ios/chrome/browser/network_activity", "//ios/chrome/test/fakes", "//ios/web/public",
diff --git a/ios/chrome/browser/download/browser_download_service.mm b/ios/chrome/browser/download/browser_download_service.mm index e28b9fb..d126f57d 100644 --- a/ios/chrome/browser/download/browser_download_service.mm +++ b/ios/chrome/browser/download/browser_download_service.mm
@@ -7,7 +7,6 @@ #include "base/metrics/histogram_macros.h" #import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" #import "ios/chrome/browser/download/download_manager_tab_helper.h" -#import "ios/chrome/browser/download/features.h" #include "ios/chrome/browser/download/pass_kit_mime_type.h" #import "ios/chrome/browser/download/pass_kit_tab_helper.h" #include "ios/chrome/browser/download/usdz_mime_type.h" @@ -112,8 +111,7 @@ tab_helper->Download(std::move(task)); } } else if (IsUsdzFileFormat(task->GetMimeType(), - task->GetSuggestedFilename()) && - download::IsUsdzPreviewEnabled()) { + task->GetSuggestedFilename())) { ARQuickLookTabHelper* tab_helper = ARQuickLookTabHelper::FromWebState(web_state); if (tab_helper) {
diff --git a/ios/chrome/browser/download/browser_download_service_unittest.mm b/ios/chrome/browser/download/browser_download_service_unittest.mm index 1ffba9b..94c66b78 100644 --- a/ios/chrome/browser/download/browser_download_service_unittest.mm +++ b/ios/chrome/browser/download/browser_download_service_unittest.mm
@@ -12,7 +12,6 @@ #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h" #import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" #import "ios/chrome/browser/download/download_manager_tab_helper.h" -#import "ios/chrome/browser/download/features.h" #include "ios/chrome/browser/download/pass_kit_mime_type.h" #import "ios/chrome/browser/download/pass_kit_tab_helper.h" #include "ios/chrome/browser/download/usdz_mime_type.h" @@ -162,12 +161,6 @@ // Tests that BrowserDownloadService uses ARQuickLookTabHelper for .USDZ // extension. TEST_F(BrowserDownloadServiceTest, UsdzExtension) { - if (!download::IsUsdzPreviewEnabled()) { - // Disabled on iOS versions below 12 because QLPreviewController is not - // available. - return; - } - ASSERT_TRUE(download_controller()->GetDelegate()); auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), "other"); task->SetSuggestedFilename(base::UTF8ToUTF16(kUsdzFileName)); @@ -186,12 +179,6 @@ // Tests that BrowserDownloadService uses ARQuickLookTabHelper for USDZ Mime // type. TEST_F(BrowserDownloadServiceTest, UsdzMimeType) { - if (!download::IsUsdzPreviewEnabled()) { - // Disabled on iOS versions below 12 because QLPreviewController is not - // available. - return; - } - ASSERT_TRUE(download_controller()->GetDelegate()); auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kUsdzMimeType); @@ -211,12 +198,6 @@ // Tests that BrowserDownloadService uses ARQuickLookTabHelper for legacy USDZ // Mime type. TEST_F(BrowserDownloadServiceTest, LegacyUsdzMimeType) { - if (!download::IsUsdzPreviewEnabled()) { - // Disabled on iOS versions below 12 because QLPreviewController is not - // available. - return; - } - ASSERT_TRUE(download_controller()->GetDelegate()); auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kLegacyUsdzMimeType); @@ -236,12 +217,6 @@ // Tests that BrowserDownloadService uses ARQuickLookTabHelper for legacy Pixar // USDZ Mime type. TEST_F(BrowserDownloadServiceTest, LegacyPixarUsdzMimeType) { - if (!download::IsUsdzPreviewEnabled()) { - // Disabled on iOS versions below 12 because QLPreviewController is not - // available. - return; - } - ASSERT_TRUE(download_controller()->GetDelegate()); auto task = std::make_unique<web::FakeDownloadTask>(GURL(kUrl), kLegacyPixarUsdzMimeType);
diff --git a/ios/chrome/browser/download/features.h b/ios/chrome/browser/download/features.h deleted file mode 100644 index 091010a..0000000 --- a/ios/chrome/browser/download/features.h +++ /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. - -#ifndef IOS_CHROME_BROWSER_DOWNLOAD_FEATURES_H_ -#define IOS_CHROME_BROWSER_DOWNLOAD_FEATURES_H_ - -namespace download { - -// Returns whether USDZ AR Quick Look is enabled. -bool IsUsdzPreviewEnabled(); - -} // namespace download - -#endif // IOS_CHROME_BROWSER_DOWNLOAD_FEATURES_H_
diff --git a/ios/chrome/browser/download/features.mm b/ios/chrome/browser/download/features.mm deleted file mode 100644 index 97a0fa7..0000000 --- a/ios/chrome/browser/download/features.mm +++ /dev/null
@@ -1,23 +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. - -#import <Foundation/Foundation.h> - -#include "ios/chrome/browser/download/features.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace download { - -// Returns whether AR Quick Look in enabled. -bool IsUsdzPreviewEnabled() { - if (@available(iOS 12, *)) { - return true; - } - return false; -} - -} // namespace download
diff --git a/ios/chrome/browser/net/ios_chrome_network_delegate.cc b/ios/chrome/browser/net/ios_chrome_network_delegate.cc index 46dcec9..27961ce 100644 --- a/ios/chrome/browser/net/ios_chrome_network_delegate.cc +++ b/ios/chrome/browser/net/ios_chrome_network_delegate.cc
@@ -124,12 +124,14 @@ bool IOSChromeNetworkDelegate::OnForcePrivacyMode( const GURL& url, - const GURL& site_for_cookies) const { + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const { // Null during tests, or when we're running in the system context. if (!cookie_settings_.get()) return false; - return !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies); + return !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies, + top_frame_origin); } bool IOSChromeNetworkDelegate::
diff --git a/ios/chrome/browser/net/ios_chrome_network_delegate.h b/ios/chrome/browser/net/ios_chrome_network_delegate.h index 1cf028e..90632ea 100644 --- a/ios/chrome/browser/net/ios_chrome_network_delegate.h +++ b/ios/chrome/browser/net/ios_chrome_network_delegate.h
@@ -63,8 +63,10 @@ bool OnCanAccessFile(const net::URLRequest& request, const base::FilePath& original_path, const base::FilePath& absolute_path) const override; - bool OnForcePrivacyMode(const GURL& url, - const GURL& site_for_cookies) const override; + bool OnForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const override; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const net::URLRequest& request, const GURL& target_url,
diff --git a/ios/chrome/browser/tabs/BUILD.gn b/ios/chrome/browser/tabs/BUILD.gn index ab23318..9b1e06e 100644 --- a/ios/chrome/browser/tabs/BUILD.gn +++ b/ios/chrome/browser/tabs/BUILD.gn
@@ -65,7 +65,6 @@ "//ios/chrome/browser/browser_state_metrics", "//ios/chrome/browser/complex_tasks", "//ios/chrome/browser/download", - "//ios/chrome/browser/download:features", "//ios/chrome/browser/favicon", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/geolocation:geolocation_internal",
diff --git a/ios/chrome/browser/tabs/tab_helper_util.mm b/ios/chrome/browser/tabs/tab_helper_util.mm index 555169f..7995189b 100644 --- a/ios/chrome/browser/tabs/tab_helper_util.mm +++ b/ios/chrome/browser/tabs/tab_helper_util.mm
@@ -19,7 +19,6 @@ #include "ios/chrome/browser/browser_state/chrome_browser_state.h" #import "ios/chrome/browser/complex_tasks/ios_task_tab_helper.h" #import "ios/chrome/browser/download/ar_quick_look_tab_helper.h" -#import "ios/chrome/browser/download/features.h" #include "ios/chrome/browser/favicon/favicon_service_factory.h" #import "ios/chrome/browser/find_in_page/find_tab_helper.h" #include "ios/chrome/browser/history/history_service_factory.h" @@ -139,9 +138,7 @@ ukm::InitializeSourceUrlRecorderForWebState(web_state); - if (download::IsUsdzPreviewEnabled()) { - ARQuickLookTabHelper::CreateForWebState(web_state); - } + ARQuickLookTabHelper::CreateForWebState(web_state); // TODO(crbug.com/794115): pre-rendered WebState have lots of unnecessary // tab helpers for historical reasons. For the moment, AttachTabHelpers
diff --git a/ios/chrome/browser/ui/autofill/BUILD.gn b/ios/chrome/browser/ui/autofill/BUILD.gn index 9f317a3..40a36d8 100644 --- a/ios/chrome/browser/ui/autofill/BUILD.gn +++ b/ios/chrome/browser/ui/autofill/BUILD.gn
@@ -84,6 +84,7 @@ "//ios/chrome/browser/ui/collection_view/cells", "//ios/chrome/browser/ui/colors", "//ios/chrome/browser/ui/util", + "//ios/chrome/common/colors", "//ios/third_party/material_components_ios", "//ios/third_party/material_roboto_font_loader_ios", "//ios/web",
diff --git a/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm b/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm index d121a08e..751adc4 100644 --- a/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm +++ b/ios/chrome/browser/ui/autofill/card_unmask_prompt_view_bridge.mm
@@ -19,8 +19,8 @@ #import "ios/chrome/browser/ui/collection_view/cells/collection_view_switch_item.h" #import "ios/chrome/browser/ui/collection_view/collection_view_controller.h" #import "ios/chrome/browser/ui/collection_view/collection_view_model.h" -#import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h" #import "ios/chrome/browser/ui/util/rtl_geometry.h" +#import "ios/chrome/common/colors/semantic_color_names.h" #import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h" #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h" #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h" @@ -176,11 +176,11 @@ target:self action:@selector(onVerify:)]; [_verifyButton setTitleTextAttributes:@{ - NSForegroundColorAttributeName : [[MDCPalette cr_bluePalette] tint600] + NSForegroundColorAttributeName : [UIColor colorNamed:kBlueColor] } forState:UIControlStateNormal]; [_verifyButton setTitleTextAttributes:@{ - NSForegroundColorAttributeName : [UIColor lightGrayColor] + NSForegroundColorAttributeName : [UIColor colorNamed:kDisabledTintColor] } forState:UIControlStateDisabled]; [_verifyButton setEnabled:NO]; @@ -521,7 +521,7 @@ base::mac::ObjCCastStrict<CollectionViewSwitchCell>(cell); storageSwitchCell.textLabel.font = [MDCTypography body2Font]; storageSwitchCell.textLabel.textColor = - [[MDCPalette greyPalette] tint500]; + [UIColor colorNamed:kTextSecondaryColor]; [storageSwitchCell.switchView addTarget:self action:@selector(onStorageSwitchChanged:) forControlEvents:UIControlEventValueChanged];
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm index 52ed4ca7..ef94ebc 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm
@@ -197,21 +197,18 @@ [[NSMutableArray alloc] init]; __weak __typeof(self) weakSelf = self; - // TODO(crbug.com/908776): fix or wait until iOS 11.2- is deprecated. - if (@available(iOS 11.3, *)) { - NSString* otherPasswordsTitleString = l10n_util::GetNSString( - IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS); - auto otherPasswordsItem = [[ManualFillActionItem alloc] - initWithTitle:otherPasswordsTitleString - action:^{ - base::RecordAction(base::UserMetricsAction( - "ManualFallback_Password_OpenOtherPassword")); - [weakSelf.navigator openAllPasswordsList]; - }]; - otherPasswordsItem.accessibilityIdentifier = - manual_fill::OtherPasswordsAccessibilityIdentifier; - [actions addObject:otherPasswordsItem]; - } + NSString* otherPasswordsTitleString = l10n_util::GetNSString( + IDS_IOS_MANUAL_FALLBACK_USE_OTHER_PASSWORD_WITH_DOTS); + auto otherPasswordsItem = [[ManualFillActionItem alloc] + initWithTitle:otherPasswordsTitleString + action:^{ + base::RecordAction(base::UserMetricsAction( + "ManualFallback_Password_OpenOtherPassword")); + [weakSelf.navigator openAllPasswordsList]; + }]; + otherPasswordsItem.accessibilityIdentifier = + manual_fill::OtherPasswordsAccessibilityIdentifier; + [actions addObject:otherPasswordsItem]; NSString* managePasswordsTitle = l10n_util::GetNSString(IDS_IOS_MANUAL_FALLBACK_MANAGE_PASSWORDS);
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm index 8a08a3a..a14b91aa 100644 --- a/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm +++ b/ios/chrome/browser/ui/autofill/manual_fill/password_view_controller_egtest.mm
@@ -328,12 +328,6 @@ // password. // TODO(crbug.com/981922): Re-enable this test due to failing DB call. - (void)DISABLED_testPasswordControllerResumes { - if (([UIDevice currentDevice].systemVersion.doubleValue < 12)) { - // TODO(crbug.com/976348): iOS 11 support is being deprecated, disable this - // failing test for now. - return; - } - // Bring up the keyboard. [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] performAction:chrome_test_util::TapWebElement(kFormElementUsername)]; @@ -373,10 +367,6 @@ // Tests that the Password View Controller is resumed after dismissing "Other // Passwords". - (void)testPasswordControllerResumesWhenOtherPasswordsDismiss { - if (([UIDevice currentDevice].systemVersion.doubleValue < 11.3)) { - // TODO(crbug.com/908776): OtherPasswordsMatcher is disabled in <11.3. - return; - } if (base::ios::IsRunningOnIOS13OrLater() && [ChromeEarlGrey isIPadIdiom]) { // TODO(crbug.com/984977): Support this behavior in iPads again. return; @@ -510,11 +500,6 @@ // Tests that after switching fields the content size of the table view didn't // grow. - (void)testPasswordControllerKeepsRightSize { - if (([UIDevice currentDevice].systemVersion.doubleValue < 11.3)) { - // TODO(crbug.com/908776): OtherPasswordsMatcher is disabled in <11.3. - return; - } - // Bring up the keyboard. [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()] performAction:chrome_test_util::TapWebElement(kFormElementUsername)];
diff --git a/ios/chrome/browser/ui/browser_view/BUILD.gn b/ios/chrome/browser/ui/browser_view/BUILD.gn index 4946272..cb91338 100644 --- a/ios/chrome/browser/ui/browser_view/BUILD.gn +++ b/ios/chrome/browser/ui/browser_view/BUILD.gn
@@ -44,7 +44,6 @@ "//ios/chrome/browser/bookmarks", "//ios/chrome/browser/browser_state", "//ios/chrome/browser/download", - "//ios/chrome/browser/download:features", "//ios/chrome/browser/feature_engagement", "//ios/chrome/browser/find_in_page", "//ios/chrome/browser/first_run",
diff --git a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm index b1483ae..5b063e9 100644 --- a/ios/chrome/browser/ui/browser_view/browser_coordinator.mm +++ b/ios/chrome/browser/ui/browser_view/browser_coordinator.mm
@@ -11,7 +11,6 @@ #import "ios/chrome/browser/app_launcher/app_launcher_tab_helper.h" #import "ios/chrome/browser/autofill/autofill_tab_helper.h" #include "ios/chrome/browser/browser_state/chrome_browser_state.h" -#import "ios/chrome/browser/download/features.h" #import "ios/chrome/browser/download/pass_kit_tab_helper.h" #import "ios/chrome/browser/main/browser.h" #import "ios/chrome/browser/store_kit/store_kit_coordinator.h" @@ -240,13 +239,11 @@ self.appLauncherCoordinator = [[AppLauncherCoordinator alloc] initWithBaseViewController:self.viewController]; - if (download::IsUsdzPreviewEnabled()) { - self.ARQuickLookCoordinator = [[ARQuickLookCoordinator alloc] - initWithBaseViewController:self.viewController - browserState:self.browserState - webStateList:self.tabModel.webStateList]; - [self.ARQuickLookCoordinator start]; - } + self.ARQuickLookCoordinator = [[ARQuickLookCoordinator alloc] + initWithBaseViewController:self.viewController + browserState:self.browserState + webStateList:self.tabModel.webStateList]; + [self.ARQuickLookCoordinator start]; self.formInputAccessoryCoordinator = [[FormInputAccessoryCoordinator alloc] initWithBaseViewController:self.viewController
diff --git a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm index 462cacd..a210f63 100644 --- a/ios/chrome/browser/ui/browser_view/browser_view_controller.mm +++ b/ios/chrome/browser/ui/browser_view/browser_view_controller.mm
@@ -3650,12 +3650,7 @@ OverscrollActionsTabHelper* activeTabHelper = OverscrollActionsTabHelper::FromWebState(currentWebState); if (controller == activeTabHelper->GetOverscrollActionsController()) { - if (!base::ios::IsRunningOnIOS12OrLater() && - self.currentWebState->GetContentsMimeType() == "application/pdf") { - return self.headerHeight - self.view.safeAreaInsets.top; - } else { - return self.headerHeight; - } + return self.headerHeight; } else return 0; }
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm index c2377af..c600302 100644 --- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm +++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -340,20 +340,8 @@ DCHECK(self.voiceSearchIsEnabled); base::RecordAction(UserMetricsAction("MobileNTPMostVisitedVoiceSearch")); UIView* voiceSearchButton = base::mac::ObjCCastStrict<UIView>(sender); - if (base::ios::IsRunningOnIOS12OrLater()) { - [NamedGuide guideWithName:kVoiceSearchButtonGuide view:voiceSearchButton] - .constrainedView = voiceSearchButton; - } else { - // On iOS 11 and below, constraining the layout guide to a view instead of - // using frame freeze the app. The root cause wasn't found. See - // https://crbug.com/874017. - NamedGuide* voiceSearchGuide = - [NamedGuide guideWithName:kVoiceSearchButtonGuide - view:voiceSearchButton]; - voiceSearchGuide.constrainedFrame = - [voiceSearchGuide.owningView convertRect:voiceSearchButton.bounds - fromView:voiceSearchButton]; - } + [NamedGuide guideWithName:kVoiceSearchButtonGuide view:voiceSearchButton] + .constrainedView = voiceSearchButton; [self.dispatcher startVoiceSearch]; }
diff --git a/ios/chrome/browser/ui/download/BUILD.gn b/ios/chrome/browser/ui/download/BUILD.gn index 14adc6f..7772055 100644 --- a/ios/chrome/browser/ui/download/BUILD.gn +++ b/ios/chrome/browser/ui/download/BUILD.gn
@@ -120,7 +120,6 @@ "//ios/chrome/app/strings", "//ios/chrome/browser:browser", "//ios/chrome/browser/download", - "//ios/chrome/browser/download:features", "//ios/chrome/browser/download:test_support", "//ios/chrome/browser/ui/browser_view", "//ios/chrome/browser/ui/util", @@ -156,7 +155,6 @@ deps = [ "//ios/chrome/app/strings:ios_strings_grit", "//ios/chrome/browser:chrome_url_constants", - "//ios/chrome/browser/download:features", "//ios/chrome/browser/download:mime_types", "//ios/chrome/browser/download:test_support", "//ios/chrome/test:eg_test_support+eg2",
diff --git a/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm b/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm index 4edb8e2cb..55f8ec5 100644 --- a/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm +++ b/ios/chrome/browser/ui/download/ar_quick_look_egtest.mm
@@ -7,7 +7,6 @@ #include "base/bind.h" #import "base/test/ios/wait_util.h" #include "ios/chrome/browser/download/download_test_util.h" -#include "ios/chrome/browser/download/features.h" #include "ios/chrome/browser/download/usdz_mime_type.h" #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" #import "ios/chrome/test/earl_grey/chrome_test_case.h" @@ -85,12 +84,6 @@ // Tests that QLPreviewController is shown for sucessfully downloaded USDZ file. - (void)testDownloadUsdz { - if (!download::IsUsdzPreviewEnabled()) { - EARL_GREY_TEST_SKIPPED( - @"Disabled if 'USDZPreview' feature is disabled or on iOS versions " - "below 12 because QLPreviewController is not available."); - } - [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; [ChromeEarlGrey waitForWebStateContainingText:"Good"]; [ChromeEarlGrey tapWebStateElementWithID:@"good"]; @@ -122,12 +115,6 @@ } - (void)testDownloadUnauthorized { - if (!download::IsUsdzPreviewEnabled()) { - EARL_GREY_TEST_SKIPPED( - @"Disabled if 'USDZPreview' feature is disabled or on iOS versions " - "below 12 because QLPreviewController is not available."); - } - [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; [ChromeEarlGrey waitForWebStateContainingText:"Unauthorized"]; [ChromeEarlGrey tapWebStateElementWithID:@"unauthorized"]; @@ -160,12 +147,6 @@ } - (void)testDownloadForbidden { - if (!download::IsUsdzPreviewEnabled()) { - EARL_GREY_TEST_SKIPPED( - @"Disabled if 'USDZPreview' feature is disabled or on iOS versions " - "below 12 because QLPreviewController is not available."); - } - [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; [ChromeEarlGrey waitForWebStateContainingText:"Forbidden"]; [ChromeEarlGrey tapWebStateElementWithID:@"forbidden"]; @@ -198,12 +179,6 @@ } - (void)testDownloadChangingMimeType { - if (!download::IsUsdzPreviewEnabled()) { - EARL_GREY_TEST_SKIPPED( - @"Disabled if 'USDZPreview' feature is disabled or on iOS versions " - "below 12 because QLPreviewController is not available."); - } - [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; [ChromeEarlGrey waitForWebStateContainingText:"Changing Mime Type"]; [ChromeEarlGrey tapWebStateElementWithID:@"changing-mime-type"];
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm index 5163e03..18f9433 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_egtest.mm
@@ -122,13 +122,10 @@ // TODO(crbug.com/618887) Replace use of specific values when API which // generates these values is exposed. CGFloat yOffset = [ChromeEarlGrey isIPadIdiom] ? -89.0 : -48.0; - if (@available(iOS 12, *)) { - // The safe area is included in the top inset as well as the toolbar - // heights. Due to crbug.com/903635, however, this only occurs on iOS 12; - // pdf rendering does not correctly account for the safe area on iOS 11. - yOffset -= - chrome_test_util::GetCurrentWebState()->GetView().safeAreaInsets.top; - } + // The safe area is included in the top inset as well as the toolbar + // heights. + yOffset -= + chrome_test_util::GetCurrentWebState()->GetView().safeAreaInsets.top; DCHECK_LT(yOffset, 0); [[EarlGrey selectElementWithMatcher:WebStateScrollViewMatcher()] assertWithMatcher:grey_scrollViewContentOffset(CGPointMake(0, yOffset))]; @@ -143,15 +140,11 @@ [ChromeEarlGrey loadURL:URL]; { - std::unique_ptr<ScopedSynchronizationDisabler> disabler = - std::make_unique<ScopedSynchronizationDisabler>(); // TODO(crbug.com/852393): Investigate why synchronization isn't working. Is // an animation going on forever? - if (@available(iOS 12, *)) { - // Disabled synchonization needs only for iOS 12. - } else { - disabler.reset(); - } + // Disabled synchonization needs only for iOS 12. + std::unique_ptr<ScopedSynchronizationDisabler> disabler = + std::make_unique<ScopedSynchronizationDisabler>(); // Test that the toolbar is still visible after a user swipes down. [[EarlGrey @@ -170,10 +163,6 @@ // Verifies that the toolbar properly appears/disappears when scrolling up/down // on a PDF that is long in length and wide in width. - (void)testLongPDFScroll { - // TODO(crbug.com/904694): This test is failing on iOS11. - if (!base::ios::IsRunningOnIOS12OrLater()) - EARL_GREY_TEST_DISABLED(@"Disabled on iOS 11."); - // TODO(crbug.com/714329): Re-enable this test on devices. #if !TARGET_IPHONE_SIMULATOR EARL_GREY_TEST_DISABLED(@"Test disabled on device.");
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm index a46baca..80cb935 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_state_observer.mm
@@ -96,18 +96,6 @@ ->GetFullscreenProvider() ->IsInitialized()); - // On iOS 12, resetting WKScrollView.contentInset at this point in the load - // will push the content down by the top inset. On iOS 11, however, this does - // not occur. Manually push the content below the toolbars the first time a - // page is loaded with the content inset setting enabled. The scroll offset - // of subsequent loads of this navigation will be set by the PageDisplayState. - web::NavigationItem* committed_item = - web_state->GetNavigationManager()->GetLastCommittedItem(); - if (use_content_inset && !base::ios::IsRunningOnIOS12OrLater() && - !committed_item->GetPageDisplayState().IsValid()) { - MoveContentBelowHeader(web_view_proxy, model_); - } - // Only reset the model for document-changing navigations or same-document // navigations that update the visible URL. if (!navigation_context->IsSameDocument() || url_changed)
diff --git a/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.mm b/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.mm index d103fb32..830ef5c 100644 --- a/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.mm +++ b/ios/chrome/browser/ui/fullscreen/fullscreen_web_view_resizer.mm
@@ -101,9 +101,6 @@ CRWWebViewScrollViewProxy* scrollViewProxy = webViewProxy.scrollViewProxy; if (self.webState->GetContentsMimeType() == "application/pdf") { - if (!base::ios::IsRunningOnIOS12OrLater()) { - insets.top -= webView.safeAreaInsets.top; - } scrollViewProxy.contentInset = insets; if (!CGRectEqualToRect(webView.frame, webView.superview.bounds)) { webView.frame = webView.superview.bounds;
diff --git a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm index 0e2e81f..45d82e4 100644 --- a/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm +++ b/ios/chrome/browser/ui/location_bar/location_bar_view_controller.mm
@@ -432,19 +432,8 @@ } - (void)startVoiceSearch { - if (base::ios::IsRunningOnIOS12OrLater()) { - [NamedGuide guideWithName:kVoiceSearchButtonGuide view:self.view] - .constrainedView = self.locationBarSteadyView.trailingButton; - } else { - // On iOS 11 and below, constraining the layout guide to a view instead of - // using frame freeze the app. The root cause wasn't found. See - // https://crbug.com/874017. - NamedGuide* voiceSearchGuide = - [NamedGuide guideWithName:kVoiceSearchButtonGuide view:self.view]; - voiceSearchGuide.constrainedFrame = [voiceSearchGuide.owningView - convertRect:self.locationBarSteadyView.trailingButton.bounds - fromView:self.locationBarSteadyView.trailingButton]; - } + [NamedGuide guideWithName:kVoiceSearchButtonGuide view:self.view] + .constrainedView = self.locationBarSteadyView.trailingButton; [self.dispatcher startVoiceSearch]; }
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn index 9454e847..0fde04e3 100644 --- a/ios/chrome/browser/ui/main/BUILD.gn +++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -23,7 +23,6 @@ "//ios/chrome/browser/crash_report:crash_report_internal", "//ios/chrome/browser/device_sharing", "//ios/chrome/browser/download", - "//ios/chrome/browser/download:features", "//ios/chrome/browser/main", "//ios/chrome/browser/reading_list", "//ios/chrome/browser/sessions",
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm index f72c7d79..ddd72cd 100644 --- a/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm +++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_icon_formatter.mm
@@ -76,7 +76,7 @@ case AutocompleteMatchType::CLIPBOARD_IMAGE: return SEARCH; case AutocompleteMatchType::SEARCH_HISTORY: - return HISTORY; + return SEARCH_HISTORY; case AutocompleteMatchType::CALCULATOR: return CALCULATOR; case AutocompleteMatchType::EXTENSION_APP_DEPRECATED:
diff --git a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm index 889cb99..4e56a11 100644 --- a/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm +++ b/ios/chrome/browser/ui/popup_menu/popup_menu_mediator.mm
@@ -874,14 +874,16 @@ } // Recent Tabs. - TableViewItem* recentTabs = CreateTableViewItem( + PopupMenuToolsItem* recentTabs = CreateTableViewItem( IDS_IOS_TOOLS_MENU_RECENT_TABS, PopupMenuActionRecentTabs, @"popup_menu_recent_tabs", kToolsMenuOtherDevicesId); + recentTabs.enabled = !self.isIncognito; // History. - TableViewItem* history = + PopupMenuToolsItem* history = CreateTableViewItem(IDS_IOS_TOOLS_MENU_HISTORY, PopupMenuActionHistory, @"popup_menu_history", kToolsMenuHistoryId); + history.enabled = !self.isIncognito; // Settings. TableViewItem* settings =
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm index 6c6d8a3..d2cab6e 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_egtest.mm
@@ -137,7 +137,8 @@ } // Tests restoring a tab from incognito when the normal WebStateList is empty. -- (void)testRestoreTabFromIncognitoWithNoNormalTabsOpen { +// TODO(crbug.com/989487): Test DISABLED, to be deleted. +- (void)DISABLED_testRestoreTabFromIncognitoWithNoNormalTabsOpen { const GURL testPageURL = web::test::HttpServer::MakeUrl(kURLOfTestPage); // Open the test page in a new tab.
diff --git a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm index 9bb2bc7..0c16b4e 100644 --- a/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm +++ b/ios/chrome/browser/ui/recent_tabs/recent_tabs_table_view_controller.mm
@@ -628,7 +628,15 @@ break; case ItemTypeShowFullHistory: [tableView deselectRowAtIndexPath:indexPath animated:NO]; - [self.presentationDelegate showHistoryFromRecentTabs]; + + // Tapping "show full history" attempts to dismiss recent tabs to show the + // history UI. It is reasonable to ignore this if a modal UI is already + // showing above recent tabs. This can happen when a user simultaneously + // taps "show full history" and "enable sync". The sync settings UI + // appears first and we should not dismiss it to display history. + if (!self.presentedViewController) { + [self.presentationDelegate showHistoryFromRecentTabs]; + } break; case ItemTypeOtherDevicesSyncOff: case ItemTypeOtherDevicesNoSessions: @@ -861,6 +869,13 @@ - (void)openTabWithContentOfDistantTab: (synced_sessions::DistantTab const*)distantTab { + // It is reasonable to ignore this request if a modal UI is already showing + // above recent tabs. This can happen when a user simultaneously taps a + // distant tab and "enable sync". The sync settings UI appears first and we + // should not dismiss it to show a distant tab. + if (self.presentedViewController) + return; + sync_sessions::OpenTabsUIDelegate* openTabs = SessionSyncServiceFactory::GetForBrowserState(self.browserState) ->GetOpenTabsUIDelegate(); @@ -896,6 +911,13 @@ - (void)openTabWithTabRestoreEntry: (const sessions::TabRestoreService::Entry*)entry { + // It is reasonable to ignore this request if a modal UI is already showing + // above recent tabs. This can happen when a user simultaneously taps a + // recently closed tab and "enable sync". The sync settings UI appears first + // and we should not dismiss it to restore a recently closed tab. + if (self.presentedViewController) + return; + // Only TAB type is handled. DCHECK_EQ(entry->type, sessions::TabRestoreService::TAB); base::RecordAction(
diff --git a/ios/chrome/browser/web/window_open_by_dom_egtest.mm b/ios/chrome/browser/web/window_open_by_dom_egtest.mm index ff3d765..625fa3a 100644 --- a/ios/chrome/browser/web/window_open_by_dom_egtest.mm +++ b/ios/chrome/browser/web/window_open_by_dom_egtest.mm
@@ -120,20 +120,12 @@ if (@available(iOS 13, *)) { // Starting from iOS 13 WebKit does not rewrite URL that ends with /..; [ChromeEarlGrey waitForMainTabCount:2]; - } else if (@available(iOS 12, *)) { + } else { // Prior to iOS 13 WebKit rewries URL that ends with /..; to invalid URL // so Chrome opens about:blank for that invalid URL. [ChromeEarlGrey waitForMainTabCount:2]; [[EarlGrey selectElementWithMatcher:OmniboxText("about:blank")] assertWithMatcher:grey_notNil()]; - } else { - // Prior to iOS 12 WebKit rewries URL that ends with /..; to invalid URL, - // but Chrome does not have a chance to open about:blank, so child window - // is not created. - [ChromeEarlGrey waitForWebStateNotContainingText:ID]; - [ChromeEarlGrey waitForMainTabCount:1]; - [[EarlGrey selectElementWithMatcher:OmniboxText("about:blank")] - assertWithMatcher:grey_notNil()]; } }
diff --git a/media/audio/fake_audio_input_stream.cc b/media/audio/fake_audio_input_stream.cc index 0c03c65..ce75d1e 100644 --- a/media/audio/fake_audio_input_stream.cc +++ b/media/audio/fake_audio_input_stream.cc
@@ -4,18 +4,29 @@ #include "media/audio/fake_audio_input_stream.h" +#include <memory> +#include <string> + #include "base/atomicops.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/macros.h" #include "base/memory/ptr_util.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_refptr.h" #include "base/single_thread_task_runner.h" #include "base/strings/string_split.h" +#include "base/synchronization/lock.h" +#include "base/thread_annotations.h" +#include "base/threading/platform_thread.h" +#include "base/threading/thread.h" #include "base/time/time.h" #include "media/audio/audio_manager_base.h" #include "media/audio/simple_sources.h" #include "media/base/audio_bus.h" +#include "media/base/audio_parameters.h" #include "media/base/media_switches.h" namespace media { @@ -33,15 +44,20 @@ FakeAudioInputStream::FakeAudioInputStream(AudioManagerBase* manager, const AudioParameters& params) : audio_manager_(manager), - callback_(NULL), - fake_audio_worker_(manager->GetWorkerTaskRunner(), params), + callback_(nullptr), params_(params), - audio_bus_(AudioBus::Create(params)) { + audio_bus_(AudioBus::Create(params)), + capture_thread_( + nullptr, + base::OnTaskRunnerDeleter(manager->GetWorkerTaskRunner())) { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); } FakeAudioInputStream::~FakeAudioInputStream() { + // |worker_| should be null as Stop() should have been called before. + DCHECK(!capture_thread_); DCHECK(!callback_); + DCHECK(!fake_audio_worker_); } bool FakeAudioInputStream::Open() { @@ -51,17 +67,49 @@ return true; } -void FakeAudioInputStream::Start(AudioInputCallback* callback) { +void FakeAudioInputStream::Start(AudioInputCallback* callback) { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); - callback_ = callback; - fake_audio_worker_.Start(base::BindRepeating( + DCHECK(!capture_thread_); + DCHECK(callback); + DCHECK(!fake_audio_worker_); + + capture_thread_.reset(new base::Thread("FakeAudioInput")); + base::Thread::Options options; + // REALTIME_AUDIO priority is needed to avoid audio playout delays. + // See crbug.com/971265 + options.priority = base::ThreadPriority::REALTIME_AUDIO; + CHECK(capture_thread_->StartWithOptions(options)); + + { + base::AutoLock lock(callback_lock_); + DCHECK(!callback_); + callback_ = callback; + } + + fake_audio_worker_ = std::make_unique<FakeAudioWorker>( + capture_thread_->task_runner(), params_); + fake_audio_worker_->Start(base::BindRepeating( &FakeAudioInputStream::ReadAudioFromSource, base::Unretained(this))); } void FakeAudioInputStream::Stop() { DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread()); - fake_audio_worker_.Stop(); - callback_ = NULL; + // Start has not been called yet. + if (!capture_thread_) { + return; + } + + { + base::AutoLock lock(callback_lock_); + DCHECK(callback_); + callback_ = nullptr; + } + + DCHECK(fake_audio_worker_); + fake_audio_worker_->Stop(); + fake_audio_worker_.reset(); + + capture_thread_.reset(); } void FakeAudioInputStream::Close() { @@ -104,8 +152,7 @@ void FakeAudioInputStream::ReadAudioFromSource(base::TimeTicks ideal_time, base::TimeTicks now) { - DCHECK(audio_manager_->GetWorkerTaskRunner()->BelongsToCurrentThread()); - DCHECK(callback_); + DCHECK(capture_thread_->task_runner()->BelongsToCurrentThread()); if (!audio_source_) audio_source_ = ChooseSource(); @@ -121,13 +168,19 @@ // // However, it would be pointless to add a FIFO queue here to delay the signal // in this "fake" implementation. So, just hack the timing and carry-on. - audio_source_->OnMoreData(base::TimeDelta(), ideal_time, 0, audio_bus_.get()); - callback_->OnData(audio_bus_.get(), ideal_time, 1.0); + { + base::AutoLock lock(callback_lock_); + if (audio_bus_ && callback_) { + audio_source_->OnMoreData(base::TimeDelta(), ideal_time, 0, + audio_bus_.get()); + callback_->OnData(audio_bus_.get(), ideal_time, 1.0); + } + } } using AudioSourceCallback = AudioOutputStream::AudioSourceCallback; std::unique_ptr<AudioSourceCallback> FakeAudioInputStream::ChooseSource() { - DCHECK(audio_manager_->GetWorkerTaskRunner()->BelongsToCurrentThread()); + DCHECK(capture_thread_->task_runner()->BelongsToCurrentThread()); if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kUseFileForFakeAudioCapture)) {
diff --git a/media/audio/fake_audio_input_stream.h b/media/audio/fake_audio_input_stream.h index 29f74dfe..b76f12f 100644 --- a/media/audio/fake_audio_input_stream.h +++ b/media/audio/fake_audio_input_stream.h
@@ -8,10 +8,13 @@ #define MEDIA_AUDIO_FAKE_AUDIO_INPUT_STREAM_H_ #include <memory> +#include <string> #include <vector> #include "base/callback_forward.h" #include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/threading/thread.h" #include "media/audio/audio_io.h" #include "media/base/audio_parameters.h" #include "media/base/fake_audio_worker.h" @@ -68,12 +71,18 @@ void ReadAudioFromSource(base::TimeTicks ideal_time, base::TimeTicks now); AudioManagerBase* audio_manager_; - AudioInputCallback* callback_; - FakeAudioWorker fake_audio_worker_; + // |callback_| needs the lock as ReadAudioFromSource reads callback_ + // on the capture thread, while callback_ is set on the audio thread. + base::Lock callback_lock_; + AudioInputCallback* callback_ GUARDED_BY(callback_lock_); AudioParameters params_; + std::unique_ptr<FakeAudioWorker> fake_audio_worker_; std::unique_ptr<AudioOutputStream::AudioSourceCallback> audio_source_; std::unique_ptr<media::AudioBus> audio_bus_; + // We will delete the capture thread on the AudioManager worker task runner + // since the audio thread is the main UI thread on Mac. + std::unique_ptr<base::Thread, base::OnTaskRunnerDeleter> capture_thread_; DISALLOW_COPY_AND_ASSIGN(FakeAudioInputStream); };
diff --git a/media/base/fake_audio_worker_unittest.cc b/media/base/fake_audio_worker_unittest.cc index 0de1edd..11569f08 100644 --- a/media/base/fake_audio_worker_unittest.cc +++ b/media/base/fake_audio_worker_unittest.cc
@@ -4,6 +4,9 @@ #include "media/base/fake_audio_worker.h" +#include <limits> +#include <memory> +#include <utility> #include <vector> #include "base/bind.h" @@ -11,7 +14,10 @@ #include "base/memory/scoped_refptr.h" #include "base/single_thread_task_runner.h" #include "base/test/scoped_task_environment.h" +#include "base/test/test_mock_time_task_runner.h" +#include "base/time/tick_clock.h" #include "base/time/time.h" +#include "base/time/time_override.h" #include "build/build_config.h" #include "media/base/audio_parameters.h" #include "testing/gmock/include/gmock/gmock-matchers.h" @@ -168,4 +174,92 @@ scoped_task_environment_.FastForwardUntilNoTasksRemain(); EXPECT_THAT(callbacks_, SizeIs(3)); } + +class FakeAudioWorkerMockTaskTest : public testing::Test { + public: + FakeAudioWorkerMockTaskTest() + : params_(AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 128), + fake_worker_(task_runner_, params_) { + DCHECK(!global_clock_); + global_clock_ = task_runner_->GetMockTickClock(); + time_between_callbacks_ = base::TimeDelta::FromMicroseconds( + params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / + static_cast<float>(params_.sample_rate())); + clock_overrides_ = std::make_unique<base::subtle::ScopedTimeClockOverrides>( + nullptr, TimeTicksOverride, nullptr); + } + + ~FakeAudioWorkerMockTaskTest() override { global_clock_ = nullptr; } + + void CalledByFakeWorker(base::TimeTicks ideal_time, base::TimeTicks now) { + callbacks_.push_back(base::TimeTicks::Now()); + } + + void SetUp() override { + { + base::TestMockTimeTaskRunner::ScopedContext ctx(task_runner_); + fake_worker_.Start( + base::BindRepeating(&FakeAudioWorkerMockTaskTest::CalledByFakeWorker, + base::Unretained(this))); + } + } + + void TearDown() override { + { + base::TestMockTimeTaskRunner::ScopedContext ctx(task_runner_); + fake_worker_.Stop(); + } + task_runner_->RunUntilIdle(); + } + + protected: + scoped_refptr<base::TestMockTimeTaskRunner> task_runner_ = + new base::TestMockTimeTaskRunner(); + std::unique_ptr<base::subtle::ScopedTimeClockOverrides> clock_overrides_; + AudioParameters params_; + FakeAudioWorker fake_worker_; + base::TimeDelta time_between_callbacks_; + std::vector<base::TimeTicks> callbacks_; + + static const base::TickClock* global_clock_; + static base::TimeTicks TimeTicksOverride() { + DCHECK(global_clock_); + return global_clock_->NowTicks(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(FakeAudioWorkerMockTaskTest); +}; + +const base::TickClock* FakeAudioWorkerMockTaskTest::global_clock_ = nullptr; + +// This test is disabled because when late we skip reading to maintain +// compatibility for input and output streams. +TEST_F(FakeAudioWorkerMockTaskTest, DISABLED_LateCallbackProducesCallback) { + task_runner_->RunUntilIdle(); + EXPECT_THAT(callbacks_, SizeIs(1)); + + // Advancing 2 periods will trigger the late logic. It should result in one + // callback, And one queued item which will run in 0.5 callback periods. + task_runner_->AdvanceMockTickClock(time_between_callbacks_ * 2.5); + task_runner_->RunUntilIdle(); + EXPECT_THAT(callbacks_, SizeIs(2)); + // Fast-forward to trigger the next time. Note that 0.5 does not work due to + // rounding in the next frame logic, since 128 does not divide 44100. + task_runner_->FastForwardBy(time_between_callbacks_ * 0.501); + EXPECT_THAT(callbacks_, SizeIs(3)); +} + +TEST_F(FakeAudioWorkerMockTaskTest, CallbackDelay) { + // Initial call only + task_runner_->RunUntilIdle(); + + // Run the clock forward 1.5 periods and then trigger the callback. + // This means we are not behind, but the next callback should occur + // in 0.5 periods. + task_runner_->AdvanceMockTickClock(time_between_callbacks_ * 1.5); + task_runner_->RunUntilIdle(); + EXPECT_THAT(callbacks_, SizeIs(2)); + EXPECT_EQ(task_runner_->NextPendingTaskDelay(), time_between_callbacks_ / 2); +} } // namespace media
diff --git a/media/gpu/v4l2/v4l2_decode_surface.cc b/media/gpu/v4l2/v4l2_decode_surface.cc index ba7f7901..ec6cab3b 100644 --- a/media/gpu/v4l2/v4l2_decode_surface.cc +++ b/media/gpu/v4l2/v4l2_decode_surface.cc
@@ -173,16 +173,19 @@ buffer->request_fd = request_fd_; buffer->flags |= V4L2_BUF_FLAG_REQUEST_FD; - // Copy the buffer index as the timestamp. + // Use the output buffer index as the timestamp. + // Since the client is supposed to keep the output buffer out of the V4L2 + // queue for as long as it is used as a reference frame, this ensures that + // all the requests we submit have unique IDs at any point in time. DCHECK_EQ(static_cast<int>(buffer->index), input_record()); buffer->timestamp.tv_sec = 0; - buffer->timestamp.tv_usec = buffer->index; + buffer->timestamp.tv_usec = output_record(); } uint64_t V4L2RequestDecodeSurface::GetReferenceID() const { // Convert the input buffer ID to what the internal representation of // the timestamp we submitted will be (tv_usec * 1000). - return input_record() * 1000; + return output_record() * 1000; } bool V4L2RequestDecodeSurface::Submit() const {
diff --git a/media/test/data/test-25fps.h264.md5 b/media/test/data/test-25fps.h264.md5 index 0aab2c20..9556c100 100644 --- a/media/test/data/test-25fps.h264.md5 +++ b/media/test/data/test-25fps.h264.md5
@@ -16,7 +16,7 @@ 82c979d493a00ee2188f7259230a8de9 # ARM - Tegra b55cda7d10c37104d8c49d27c2699e40 -# ARM - MediaTek +# ARM - Mediatek MT8173 af21b8aa5ea63c4e88f0472ee948d01a # ARM - Cheza e0ae5fbb0ef06922ae13b84e001f263c @@ -24,3 +24,5 @@ 7ad287d048d6bdee63fbe37a3cd2c760 # ARM - AMLogic - T931 4c183194e3596b579af75f8a04b9eaa9 +# ARM - Mediatek MT8183 +583c8a95ebd13337bd2e5c59510e5d15
diff --git a/net/base/layered_network_delegate.cc b/net/base/layered_network_delegate.cc index 9f47088..f901dccc 100644 --- a/net/base/layered_network_delegate.cc +++ b/net/base/layered_network_delegate.cc
@@ -229,14 +229,17 @@ bool LayeredNetworkDelegate::OnForcePrivacyMode( const GURL& url, - const GURL& site_for_cookies) const { - return OnForcePrivacyModeInternal(url, site_for_cookies) || - nested_network_delegate_->ForcePrivacyMode(url, site_for_cookies); + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const { + return OnForcePrivacyModeInternal(url, site_for_cookies, top_frame_origin) || + nested_network_delegate_->ForcePrivacyMode(url, site_for_cookies, + top_frame_origin); } bool LayeredNetworkDelegate::OnForcePrivacyModeInternal( const GURL& url, - const GURL& site_for_cookies) const { + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const { return false; }
diff --git a/net/base/layered_network_delegate.h b/net/base/layered_network_delegate.h index 9c65037b..e8c855c 100644 --- a/net/base/layered_network_delegate.h +++ b/net/base/layered_network_delegate.h
@@ -89,8 +89,10 @@ bool OnCanAccessFile(const URLRequest& request, const base::FilePath& original_path, const base::FilePath& absolute_path) const final; - bool OnForcePrivacyMode(const GURL& url, - const GURL& site_for_cookies) const final; + bool OnForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const final; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, const GURL& target_url, @@ -170,8 +172,10 @@ // If this returns false, it short circuits the corresponding call in any // nested NetworkDelegates. - virtual bool OnForcePrivacyModeInternal(const GURL& url, - const GURL& site_for_cookies) const; + virtual bool OnForcePrivacyModeInternal( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const; // If this returns false, it short circuits the corresponding call in any // nested NetworkDelegates.
diff --git a/net/base/layered_network_delegate_unittest.cc b/net/base/layered_network_delegate_unittest.cc index b6b867e..ece2eb9 100644 --- a/net/base/layered_network_delegate_unittest.cc +++ b/net/base/layered_network_delegate_unittest.cc
@@ -12,6 +12,7 @@ #include "base/files/file_path.h" #include "base/macros.h" #include "base/memory/ref_counted.h" +#include "base/optional.h" #include "net/base/auth.h" #include "net/base/net_errors.h" #include "net/base/network_delegate_impl.h" @@ -137,8 +138,10 @@ return false; } - bool OnForcePrivacyMode(const GURL& url, - const GURL& site_for_cookies) const override { + bool OnForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const override { IncrementAndCompareCounter("on_force_privacy_mode_count"); return false; } @@ -211,7 +214,7 @@ EXPECT_FALSE( OnCanSetCookie(*request, net::CanonicalCookie(), nullptr, true)); EXPECT_FALSE(OnCanAccessFile(*request, base::FilePath(), base::FilePath())); - EXPECT_FALSE(OnForcePrivacyMode(GURL(), GURL())); + EXPECT_FALSE(OnForcePrivacyMode(GURL(), GURL(), base::nullopt)); EXPECT_FALSE(OnCancelURLRequestWithPolicyViolatingReferrerHeader( *request, GURL(), GURL())); } @@ -325,8 +328,10 @@ EXPECT_EQ(1, (*counters_)["on_can_access_file_count"]); } - bool OnForcePrivacyModeInternal(const GURL& url, - const GURL& site_for_cookies) const override { + bool OnForcePrivacyModeInternal( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const override { ++(*counters_)["on_force_privacy_mode_count"]; EXPECT_EQ(1, (*counters_)["on_force_privacy_mode_count"]); return false;
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc index d0f2453..dae5c827 100644 --- a/net/base/network_delegate.cc +++ b/net/base/network_delegate.cc
@@ -165,11 +165,13 @@ return OnCanAccessFile(request, original_path, absolute_path); } -bool NetworkDelegate::ForcePrivacyMode(const GURL& url, - const GURL& site_for_cookies) const { +bool NetworkDelegate::ForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const { TRACE_EVENT0(NetTracingCategory(), "NetworkDelegate::ForcePrivacyMode"); DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - return OnForcePrivacyMode(url, site_for_cookies); + return OnForcePrivacyMode(url, site_for_cookies, top_frame_origin); } bool NetworkDelegate::CancelURLRequestWithPolicyViolatingReferrerHeader(
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h index 49fe875c..e511559b 100644 --- a/net/base/network_delegate.h +++ b/net/base/network_delegate.h
@@ -106,7 +106,10 @@ bool CanAccessFile(const URLRequest& request, const base::FilePath& original_path, const base::FilePath& absolute_path) const; - bool ForcePrivacyMode(const GURL& url, const GURL& site_for_cookies) const; + bool ForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const; bool CancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request, @@ -316,8 +319,10 @@ // Returns true if the given |url| has to be requested over connection that // is not tracked by the server. Usually is false, unless user privacy // settings block cookies from being get or set. - virtual bool OnForcePrivacyMode(const GURL& url, - const GURL& site_for_cookies) const = 0; + virtual bool OnForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const = 0; // Called when the |referrer_url| for requesting |target_url| during handling // of the |request| is does not comply with the referrer policy (e.g. a
diff --git a/net/base/network_delegate_impl.cc b/net/base/network_delegate_impl.cc index e6656f5..088e5eb 100644 --- a/net/base/network_delegate_impl.cc +++ b/net/base/network_delegate_impl.cc
@@ -93,7 +93,8 @@ bool NetworkDelegateImpl::OnForcePrivacyMode( const GURL& url, - const GURL& site_for_cookies) const { + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const { return false; }
diff --git a/net/base/network_delegate_impl.h b/net/base/network_delegate_impl.h index e1c0fa7..bde4910 100644 --- a/net/base/network_delegate_impl.h +++ b/net/base/network_delegate_impl.h
@@ -95,8 +95,10 @@ const base::FilePath& original_path, const base::FilePath& absolute_path) const override; - bool OnForcePrivacyMode(const GURL& url, - const GURL& site_for_cookies) const override; + bool OnForcePrivacyMode( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const override; bool OnCancelURLRequestWithPolicyViolatingReferrerHeader( const URLRequest& request,
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 736dddb..5fec727 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -1155,8 +1155,8 @@ // with the network service - remove it. bool enable_privacy_mode = !g_default_can_use_cookies; if (network_delegate_) { - enable_privacy_mode = - network_delegate_->ForcePrivacyMode(url(), site_for_cookies_); + enable_privacy_mode = network_delegate_->ForcePrivacyMode( + url(), site_for_cookies_, network_isolation_key_.GetTopFrameOrigin()); } return enable_privacy_mode ? PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED; }
diff --git a/printing/BUILD.gn b/printing/BUILD.gn index 5fe480f5..9f1696ce 100644 --- a/printing/BUILD.gn +++ b/printing/BUILD.gn
@@ -82,6 +82,7 @@ "units.h", ] + configs += [ "//build/config/compiler:noshadowing" ] cflags = [] defines = [ "PRINTING_IMPLEMENTATION" ] @@ -274,6 +275,7 @@ sources += [ "image_fuchsia.cc" ] } + configs += [ "//build/config/compiler:noshadowing" ] public_deps = [ "//printing", "//ui/gfx/geometry", @@ -301,6 +303,7 @@ "units_unittest.cc", ] + configs += [ "//build/config/compiler:noshadowing" ] deps = [ ":printing", "//base/test:run_all_unittests",
diff --git a/remoting/host/file_transfer/local_file_operations.cc b/remoting/host/file_transfer/local_file_operations.cc index b09064a6..ef38677 100644 --- a/remoting/host/file_transfer/local_file_operations.cc +++ b/remoting/host/file_transfer/local_file_operations.cc
@@ -393,7 +393,7 @@ PostTaskAndReplyWithResult( file_task_runner_.get(), FROM_HERE, base::BindOnce(&base::GetUniquePathNumber, temp_filepath, - base::FilePath::StringType()), + base::FilePath::StringPieceType()), base::BindOnce(&LocalFileWriter::CreateTempFile, weak_ptr_factory_.GetWeakPtr(), std::move(callback), temp_filepath)); @@ -492,7 +492,7 @@ base::PostTaskAndReplyWithResult( file_task_runner_.get(), FROM_HERE, base::BindOnce(&base::GetUniquePathNumber, destination_filepath_, - base::FilePath::StringType()), + base::FilePath::StringPieceType()), base::BindOnce(&LocalFileWriter::MoveToDestination, weak_ptr_factory_.GetWeakPtr(), std::move(callback))); }
diff --git a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java index ee7de36..ef4f305 100644 --- a/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java +++ b/services/device/nfc/android/java/src/org/chromium/device/nfc/NfcImpl.java
@@ -382,7 +382,9 @@ private NfcError checkIfReady() { if (!mHasPermission || mActivity == null) { return createError(NfcErrorType.NOT_ALLOWED); - } else if (mNfcManager == null || mNfcAdapter == null || !mNfcAdapter.isEnabled()) { + } else if (mNfcManager == null || mNfcAdapter == null) { + return createError(NfcErrorType.NOT_SUPPORTED); + } else if (!mNfcAdapter.isEnabled()) { return createError(NfcErrorType.NOT_READABLE); } return null;
diff --git a/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java b/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java index 9b41ca5..d62b75f6 100644 --- a/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java +++ b/services/device/nfc/android/junit/src/org/chromium/device/nfc/NFCTest.java
@@ -163,7 +163,7 @@ } /** - * Test that error with type NOT_READABLE is returned if NFC is not supported. + * Test that error with type NOT_SUPPORTED is returned if NFC is not supported. */ @Test @Feature({"NFCTest"}) @@ -174,7 +174,7 @@ CancelAllWatchesResponse mockCallback = mock(CancelAllWatchesResponse.class); nfc.cancelAllWatches(mockCallback); verify(mockCallback).call(mErrorCaptor.capture()); - assertEquals(NfcErrorType.NOT_READABLE, mErrorCaptor.getValue().errorType); + assertEquals(NfcErrorType.NOT_SUPPORTED, mErrorCaptor.getValue().errorType); } /**
diff --git a/services/device/public/mojom/nfc.mojom b/services/device/public/mojom/nfc.mojom index 3f4afc7b..a002b12 100644 --- a/services/device/public/mojom/nfc.mojom +++ b/services/device/public/mojom/nfc.mojom
@@ -7,10 +7,10 @@ enum NFCErrorType { // No permssion. NOT_ALLOWED, - // Operation is not supported by the NFC Adapter + // No hardware support, no NFC adapter, the connection cannot be established, + // or operation is not supported by the NFC Adapter. NOT_SUPPORTED, - // No hardware support, no NFC adapter or the adapter is disabled, - // or the connection cannot be established. + // NFC adapter is disabled. NOT_READABLE, NOT_FOUND, INVALID_MESSAGE,
diff --git a/services/network/cookie_settings.cc b/services/network/cookie_settings.cc index 0f56483..14c953d 100644 --- a/services/network/cookie_settings.cc +++ b/services/network/cookie_settings.cc
@@ -7,8 +7,6 @@ #include <functional> #include "base/bind.h" -#include "net/base/net_errors.h" -#include "net/base/static_cookie_policy.h" namespace network { namespace { @@ -30,10 +28,12 @@ std::cref(content_settings_)); } -void CookieSettings::GetCookieSetting(const GURL& url, - const GURL& first_party_url, - content_settings::SettingSource* source, - ContentSetting* cookie_setting) const { +void CookieSettings::GetCookieSettingInternal( + const GURL& url, + const GURL& first_party_url, + bool is_third_party_request, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const { if (base::Contains(secure_origin_cookies_allowed_schemes_, first_party_url.scheme()) && url.SchemeIsCryptographic()) { @@ -64,9 +64,7 @@ } } - net::StaticCookiePolicy policy( - net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES); - if (block_third && policy.CanAccessCookies(url, first_party_url) != net::OK) + if (block_third && is_third_party_request) *cookie_setting = CONTENT_SETTING_BLOCK; }
diff --git a/services/network/cookie_settings.h b/services/network/cookie_settings.h index 578af6b3..3781493 100644 --- a/services/network/cookie_settings.h +++ b/services/network/cookie_settings.h
@@ -59,13 +59,14 @@ SessionCleanupCookieStore::DeleteCookiePredicate CreateDeleteCookieOnExitPredicate() const; - // content_settings::CookieSettingsBase: - void GetCookieSetting(const GURL& url, - const GURL& first_party_url, - content_settings::SettingSource* source, - ContentSetting* cookie_setting) const override; - private: + // content_settings::CookieSettingsBase: + void GetCookieSettingInternal(const GURL& url, + const GURL& first_party_url, + bool is_third_party_request, + content_settings::SettingSource* source, + ContentSetting* cookie_setting) const override; + // Returns true if at least one content settings is session only. bool HasSessionOnlyOrigins() const;
diff --git a/services/network/network_context.cc b/services/network/network_context.cc index ae8288e..9923e19a 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc
@@ -61,6 +61,7 @@ #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/report_sender.h" #include "net/url_request/static_http_user_agent_settings.h" +#include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "services/network/cookie_manager.h" @@ -441,8 +442,9 @@ return allowed_from_caller && network_context_->cookie_manager() ->cookie_settings() - .IsCookieAccessAllowed(request.url(), - request.site_for_cookies()); + .IsCookieAccessAllowed( + request.url(), request.site_for_cookies(), + request.network_isolation_key().GetTopFrameOrigin()); } bool OnCanSetCookieInternal(const net::URLRequest& request, @@ -452,15 +454,18 @@ return allowed_from_caller && network_context_->cookie_manager() ->cookie_settings() - .IsCookieAccessAllowed(request.url(), - request.site_for_cookies()); + .IsCookieAccessAllowed( + request.url(), request.site_for_cookies(), + request.network_isolation_key().GetTopFrameOrigin()); } - bool OnForcePrivacyModeInternal(const GURL& url, - const GURL& site_for_cookies) const override { + bool OnForcePrivacyModeInternal( + const GURL& url, + const GURL& site_for_cookies, + const base::Optional<url::Origin>& top_frame_origin) const override { return !network_context_->cookie_manager() ->cookie_settings() - .IsCookieAccessAllowed(url, site_for_cookies); + .IsCookieAccessAllowed(url, site_for_cookies, top_frame_origin); } void OnResponseStartedInternal(net::URLRequest* request,
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index f794703..52c9080 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -134,6 +134,8 @@ const GURL kURL("http://foo.com"); const GURL kOtherURL("http://other.com"); +const url::Origin kOrigin = url::Origin::Create(kURL); +const url::Origin kOtherOrigin = url::Origin::Create(kOtherURL); constexpr char kMockHost[] = "mock.host"; constexpr char kCustomProxyResponse[] = "CustomProxyResponse"; constexpr int kProcessId = 11; @@ -3233,7 +3235,7 @@ EXPECT_FALSE(network_context->url_request_context() ->network_delegate() - ->ForcePrivacyMode(kURL, kOtherURL)); + ->ForcePrivacyMode(kURL, kOtherURL, kOtherOrigin)); } TEST_F(NetworkContextTest, PrivacyModeEnabledIfCookiesBlocked) { @@ -3244,10 +3246,10 @@ network_context.get()); EXPECT_TRUE(network_context->url_request_context() ->network_delegate() - ->ForcePrivacyMode(kURL, kOtherURL)); + ->ForcePrivacyMode(kURL, kOtherURL, kOtherOrigin)); EXPECT_FALSE(network_context->url_request_context() ->network_delegate() - ->ForcePrivacyMode(kOtherURL, kURL)); + ->ForcePrivacyMode(kOtherURL, kURL, kOrigin)); } TEST_F(NetworkContextTest, PrivacyModeDisabledIfCookiesAllowed) { @@ -3258,7 +3260,7 @@ network_context.get()); EXPECT_FALSE(network_context->url_request_context() ->network_delegate() - ->ForcePrivacyMode(kURL, kOtherURL)); + ->ForcePrivacyMode(kURL, kOtherURL, kOtherOrigin)); } TEST_F(NetworkContextTest, PrivacyModeDisabledIfCookiesSettingForOtherURL) { @@ -3270,7 +3272,7 @@ network_context.get()); EXPECT_FALSE(network_context->url_request_context() ->network_delegate() - ->ForcePrivacyMode(kURL, kOtherURL)); + ->ForcePrivacyMode(kURL, kOtherURL, kOtherOrigin)); } TEST_F(NetworkContextTest, PrivacyModeEnabledIfThirdPartyCookiesBlocked) { @@ -3280,12 +3282,12 @@ network_context->url_request_context()->network_delegate(); network_context->cookie_manager()->BlockThirdPartyCookies(true); - EXPECT_TRUE(delegate->ForcePrivacyMode(kURL, kOtherURL)); - EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kURL)); + EXPECT_TRUE(delegate->ForcePrivacyMode(kURL, kOtherURL, kOtherOrigin)); + EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kURL, kOrigin)); network_context->cookie_manager()->BlockThirdPartyCookies(false); - EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kOtherURL)); - EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kURL)); + EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kOtherURL, kOtherOrigin)); + EXPECT_FALSE(delegate->ForcePrivacyMode(kURL, kURL, kOrigin)); } TEST_F(NetworkContextTest, CanSetCookieFalseIfCookiesBlocked) { @@ -5564,6 +5566,7 @@ ResourceRequest first_party_request; first_party_request.url = server_url; first_party_request.site_for_cookies = first_party_url; + first_party_request.top_frame_origin = url::Origin::Create(first_party_url); std::unique_ptr<TestURLLoaderClient> client = FetchRequest( first_party_request, network_context.get(), url_loader_options); @@ -5577,6 +5580,7 @@ ResourceRequest third_party_request; third_party_request.url = server_url; third_party_request.site_for_cookies = third_party_url; + third_party_request.top_frame_origin = url::Origin::Create(third_party_url); client = FetchRequest(third_party_request, network_context.get(), url_loader_options); @@ -5608,6 +5612,7 @@ ResourceRequest first_party_request; first_party_request.url = server_url; first_party_request.site_for_cookies = first_party_url; + first_party_request.top_frame_origin = url::Origin::Create(first_party_url); std::unique_ptr<TestURLLoaderClient> client = FetchRequest( first_party_request, network_context.get(), url_loader_options); @@ -5621,6 +5626,7 @@ ResourceRequest third_party_request; third_party_request.url = server_url; third_party_request.site_for_cookies = third_party_url; + third_party_request.top_frame_origin = url::Origin::Create(third_party_url); client = FetchRequest(third_party_request, network_context.get(), url_loader_options); @@ -5652,6 +5658,7 @@ ResourceRequest first_party_request; first_party_request.url = server_url; first_party_request.site_for_cookies = first_party_url; + first_party_request.top_frame_origin = url::Origin::Create(first_party_url); std::unique_ptr<TestURLLoaderClient> client = FetchRequest( first_party_request, network_context.get(), url_loader_options); @@ -5665,6 +5672,7 @@ ResourceRequest third_party_request; third_party_request.url = server_url; third_party_request.site_for_cookies = third_party_url; + third_party_request.top_frame_origin = url::Origin::Create(third_party_url); client = FetchRequest(third_party_request, network_context.get(), url_loader_options);
diff --git a/services/network/public/mojom/restricted_cookie_manager.mojom b/services/network/public/mojom/restricted_cookie_manager.mojom index daf226d..8f487f1 100644 --- a/services/network/public/mojom/restricted_cookie_manager.mojom +++ b/services/network/public/mojom/restricted_cookie_manager.mojom
@@ -7,6 +7,7 @@ import "services/network/public/mojom/cookie_manager.mojom"; import "mojo/public/mojom/base/time.mojom"; import "url/mojom/url.mojom"; +import "url/mojom/origin.mojom"; enum CookieMatchType { EQUALS, @@ -56,19 +57,26 @@ // |url| is an URL capable of receiving HTTP requests. |site_for_cookies| is // the "site for cookies" values defined in RFC 6265bis, and roughly maps to // the URL of the top-level frame in Document contexts, and to the script URL - // in service workers. |options| filters the returned list of cookies. + // in service workers. |top_frame_origin| is the actual origin of the top + // level frame or the script url for service workers. |site_for_cookies| is + // used to determine if a cookie is accessed in a third-party context. + // |top_frame_origin| is used to check for content settings. + // |options| filters the returned list of cookies. GetAllForUrl( url.mojom.Url url, url.mojom.Url site_for_cookies, + url.mojom.Origin top_frame_origin, CookieManagerGetOptions options) => (array<CanonicalCookie> cookies); SetCanonicalCookie(CanonicalCookie cookie, url.mojom.Url url, - url.mojom.Url site_for_cookies) => (bool success); + url.mojom.Url site_for_cookies, + url.mojom.Origin top_frame_origin) => (bool success); // Subscribes to changes in the cookies transmitted in a request to an URL. // // The subscription is canceled by closing the pipe. AddChangeListener(url.mojom.Url url, url.mojom.Url site_for_cookies, + url.mojom.Origin top_frame_origin, CookieChangeListener listener) => (); // Sets a cookie. If setting of this cookie is not permitted either by web @@ -81,6 +89,7 @@ // to serialize with other operations. [Sync] SetCookieFromString(url.mojom.Url url, url.mojom.Url site_for_cookies, + url.mojom.Origin top_frame_origin, string cookie) => (); // Used to get cookies for the given URL. Cookies that are blocked by user @@ -92,7 +101,8 @@ // is bounded to will be treated as the renderer violating security rules. [Sync] GetCookiesString(url.mojom.Url url, - url.mojom.Url site_for_cookies) => (string cookies); + url.mojom.Url site_for_cookies, + url.mojom.Origin top_frame_origin) => (string cookies); // Used to check if cookies are enabled for the given URL in context of a // given site. @@ -100,6 +110,8 @@ // Passing in |url| that does not match the origin RestrictedCookieManager // is bounded to will be treated as the renderer violating security rules. [Sync] - CookiesEnabledFor(url.mojom.Url url, - url.mojom.Url site_for_cookies) => (bool cookies_enabled); + CookiesEnabledFor( + url.mojom.Url url, + url.mojom.Url site_for_cookies, + url.mojom.Origin top_frame_origin) => (bool cookies_enabled); };
diff --git a/services/network/restricted_cookie_manager.cc b/services/network/restricted_cookie_manager.cc index 3cba583e..02e5f75d 100644 --- a/services/network/restricted_cookie_manager.cc +++ b/services/network/restricted_cookie_manager.cc
@@ -78,11 +78,13 @@ const RestrictedCookieManager* restricted_cookie_manager, const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, net::CookieOptions options, mojom::CookieChangeListenerPtr mojo_listener) : restricted_cookie_manager_(restricted_cookie_manager), url_(url), site_for_cookies_(site_for_cookies), + top_frame_origin_(top_frame_origin), options_(options), mojo_listener_(std::move(mojo_listener)) { // TODO(pwnall): add a constructor w/options to net::CookieChangeDispatcher. @@ -119,7 +121,7 @@ // being deleted at a later time, which can happen due to eviction or due to // the user explicitly deleting all cookies. if (!restricted_cookie_manager_->cookie_settings()->IsCookieAccessAllowed( - url_, site_for_cookies_)) + url_, site_for_cookies_, top_frame_origin_)) return; mojo_listener_->OnCookieChange(cookie, ToCookieChangeCause(cause)); @@ -135,9 +137,13 @@ // The URL whose cookies this listener is interested in. const GURL url_; - // Site context in which we're used; used for permission-checking. + // Site context in which we're used; used to determine if a cookie is accessed + // in a third-party context. const GURL site_for_cookies_; + // Site context in which we're used; used to check content settings. + const url::Origin top_frame_origin_; + // CanonicalCookie::IncludeForRequestURL options for this listener's interest. const net::CookieOptions options_; @@ -183,6 +189,7 @@ void RestrictedCookieManager::GetAllForUrl( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, mojom::CookieManagerGetOptionsPtr options, GetAllForUrlCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -204,12 +211,14 @@ url, net_options, base::BindOnce(&RestrictedCookieManager::CookieListToGetAllForUrlCallback, weak_ptr_factory_.GetWeakPtr(), url, site_for_cookies, - net_options, std::move(options), std::move(callback))); + top_frame_origin, net_options, std::move(options), + std::move(callback))); } void RestrictedCookieManager::CookieListToGetAllForUrlCallback( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const net::CookieOptions& net_options, mojom::CookieManagerGetOptionsPtr options, GetAllForUrlCallback callback, @@ -217,8 +226,8 @@ const net::CookieStatusList& excluded_cookies) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - bool blocked = - !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies); + bool blocked = !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies, + top_frame_origin); std::vector<net::CanonicalCookie> result; std::vector<net::CookieWithStatus> result_with_status; @@ -294,6 +303,7 @@ const net::CanonicalCookie& cookie, const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, SetCanonicalCookieCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); if (!ValidateAccessToCookiesAt(url)) { @@ -302,8 +312,8 @@ } // TODO(morlovich): Try to validate site_for_cookies as well. - bool blocked = - !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies); + bool blocked = !cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies, + top_frame_origin); if (blocked) { if (network_context_client_) { @@ -376,6 +386,7 @@ void RestrictedCookieManager::AddChangeListener( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, mojom::CookieChangeListenerPtr mojo_listener, AddChangeListenerCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -386,9 +397,9 @@ net::CookieOptions net_options = MakeOptionsForGet(role_, url, site_for_cookies); - auto listener = - std::make_unique<Listener>(cookie_store_, this, url, site_for_cookies, - net_options, std::move(mojo_listener)); + auto listener = std::make_unique<Listener>( + cookie_store_, this, url, site_for_cookies, top_frame_origin, net_options, + std::move(mojo_listener)); listener->mojo_listener().set_connection_error_handler( base::BindOnce(&RestrictedCookieManager::RemoveChangeListener, @@ -406,6 +417,7 @@ void RestrictedCookieManager::SetCookieFromString( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const std::string& cookie, SetCookieFromStringCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); @@ -421,7 +433,7 @@ // Further checks (origin_, settings), as well as logging done by // SetCanonicalCookie() SetCanonicalCookie( - *parsed_cookie, url, site_for_cookies, + *parsed_cookie, url, site_for_cookies, top_frame_origin, base::BindOnce([](SetCookieFromStringCallback user_callback, bool success) { std::move(user_callback).Run(); }, std::move(callback))); @@ -430,6 +442,7 @@ void RestrictedCookieManager::GetCookiesString( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, GetCookiesStringCallback callback) { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); // Checks done by GetAllForUrl. @@ -438,7 +451,8 @@ auto match_options = mojom::CookieManagerGetOptions::New(); match_options->name = ""; match_options->match_type = mojom::CookieMatchType::STARTS_WITH; - GetAllForUrl(url, site_for_cookies, std::move(match_options), + GetAllForUrl(url, site_for_cookies, top_frame_origin, + std::move(match_options), base::BindOnce( [](GetCookiesStringCallback user_callback, const std::vector<net::CanonicalCookie>& cookies) { @@ -451,14 +465,15 @@ void RestrictedCookieManager::CookiesEnabledFor( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, CookiesEnabledForCallback callback) { if (!ValidateAccessToCookiesAt(url)) { std::move(callback).Run(false); return; } - std::move(callback).Run( - cookie_settings_->IsCookieAccessAllowed(url, site_for_cookies)); + std::move(callback).Run(cookie_settings_->IsCookieAccessAllowed( + url, site_for_cookies, top_frame_origin)); } void RestrictedCookieManager::RemoveChangeListener(Listener* listener) {
diff --git a/services/network/restricted_cookie_manager.h b/services/network/restricted_cookie_manager.h index 6f00581da..0eb1cc7 100644 --- a/services/network/restricted_cookie_manager.h +++ b/services/network/restricted_cookie_manager.h
@@ -60,29 +60,35 @@ void GetAllForUrl(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, mojom::CookieManagerGetOptionsPtr options, GetAllForUrlCallback callback) override; void SetCanonicalCookie(const net::CanonicalCookie& cookie, const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, SetCanonicalCookieCallback callback) override; void AddChangeListener(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, mojom::CookieChangeListenerPtr listener, AddChangeListenerCallback callback) override; void SetCookieFromString(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const std::string& cookie, SetCookieFromStringCallback callback) override; void GetCookiesString(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, GetCookiesStringCallback callback) override; void CookiesEnabledFor(const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, CookiesEnabledForCallback callback) override; private: @@ -93,6 +99,7 @@ void CookieListToGetAllForUrlCallback( const GURL& url, const GURL& site_for_cookies, + const url::Origin& top_frame_origin, const net::CookieOptions& net_options, mojom::CookieManagerGetOptionsPtr options, GetAllForUrlCallback callback,
diff --git a/services/network/restricted_cookie_manager_unittest.cc b/services/network/restricted_cookie_manager_unittest.cc index 844379d..a545827 100644 --- a/services/network/restricted_cookie_manager_unittest.cc +++ b/services/network/restricted_cookie_manager_unittest.cc
@@ -111,7 +111,8 @@ base::RunLoop run_loop; std::vector<net::CanonicalCookie> result; cookie_service_->GetAllForUrl( - url, site_for_cookies, std::move(options), + url, site_for_cookies, url::Origin::Create(site_for_cookies), + std::move(options), base::BindLambdaForTesting( [&run_loop, &result](const std::vector<net::CanonicalCookie>& backend_result) { @@ -128,7 +129,7 @@ base::RunLoop run_loop; bool result = false; cookie_service_->SetCanonicalCookie( - cookie, url, site_for_cookies, + cookie, url, site_for_cookies, url::Origin::Create(site_for_cookies), base::BindLambdaForTesting([&run_loop, &result](bool backend_result) { result = backend_result; run_loop.Quit(); @@ -142,7 +143,8 @@ mojom::CookieChangeListenerPtr listener) { base::RunLoop run_loop; cookie_service_->AddChangeListener( - url, site_for_cookies, std::move(listener), run_loop.QuitClosure()); + url, site_for_cookies, url::Origin::Create(site_for_cookies), + std::move(listener), run_loop.QuitClosure()); run_loop.Run(); } @@ -296,9 +298,9 @@ // Can also use the document.cookie-style API to get the same info. std::string cookies_out; - EXPECT_TRUE(backend()->GetCookiesString(GURL("http://example.com/test/"), - GURL("http://example.com"), - &cookies_out)); + EXPECT_TRUE(backend()->GetCookiesString( + GURL("http://example.com/test/"), GURL("http://example.com"), + url::Origin::Create(GURL("http://example.com")), &cookies_out)); EXPECT_EQ("cookie-name=cookie-value; cookie-name-2=cookie-value-2", cookies_out); } @@ -408,9 +410,9 @@ ExpectBadMessage(); std::string cookies_out; - EXPECT_TRUE(backend()->GetCookiesString(GURL("http://notexample.com/test/"), - GURL("http://example.com"), - &cookies_out)); + EXPECT_TRUE(backend()->GetCookiesString( + GURL("http://notexample.com/test/"), GURL("http://example.com"), + url::Origin::Create(GURL("http://example.com")), &cookies_out)); EXPECT_TRUE(received_bad_message()); EXPECT_TRUE(cookies_out.empty()); } @@ -559,9 +561,10 @@ } TEST_P(RestrictedCookieManagerTest, SetCookieFromString) { - EXPECT_TRUE(backend()->SetCookieFromString(GURL("http://example.com/test/"), - GURL("http://example.com"), - "new-name=new-value;path=/")); + EXPECT_TRUE(backend()->SetCookieFromString( + GURL("http://example.com/test/"), GURL("http://example.com"), + url::Origin::Create(GURL("http://example.com")), + "new-name=new-value;path=/")); auto options = mojom::CookieManagerGetOptions::New(); options->name = "new-name"; options->match_type = mojom::CookieMatchType::EQUALS; @@ -591,6 +594,7 @@ ExpectBadMessage(); EXPECT_TRUE(backend()->SetCookieFromString( GURL("http://notexample.com/test/"), GURL("http://example.com"), + url::Origin::Create(GURL("http://example.com")), "new-name=new-value;path=/")); ASSERT_TRUE(received_bad_message()); } @@ -688,18 +692,21 @@ // Default, third-party access is OK. bool result = false; EXPECT_TRUE(backend()->CookiesEnabledFor( - GURL("http://example.com"), GURL("http://notexample.com"), &result)); + GURL("http://example.com"), GURL("http://notexample.com"), + url::Origin::Create(GURL("http://notexample.com")), &result)); EXPECT_TRUE(result); // Third-part cookies disabled. cookie_settings_.set_block_third_party_cookies(true); EXPECT_TRUE(backend()->CookiesEnabledFor( - GURL("http://example.com"), GURL("http://notexample.com"), &result)); + GURL("http://example.com"), GURL("http://notexample.com"), + url::Origin::Create(GURL("http://notexample.com")), &result)); EXPECT_FALSE(result); // First-party ones still OK. EXPECT_TRUE(backend()->CookiesEnabledFor( - GURL("http://example.com"), GURL("http://example.com"), &result)); + GURL("http://example.com"), GURL("http://example.com"), + url::Origin::Create(GURL("http://example.com")), &result)); EXPECT_TRUE(result); }
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json index 3814828..7b358af 100644 --- a/testing/buildbot/chromium.fyi.json +++ b/testing/buildbot/chromium.fyi.json
@@ -1,11 +1,6 @@ { "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, "AAAAA2 See generate_buildbot_json.py to make changes": {}, - "Android Builder (dbg) Goma Canary": { - "additional_compile_targets": [ - "all" - ] - }, "Jumbo Linux x64": { "additional_compile_targets": [ "all" @@ -205,80 +200,6 @@ } ] }, - "Linux x64 Goma Canary (clobber)": { - "additional_compile_targets": [ - "all" - ], - "gtest_tests": [ - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ] - }, - "test": "base_unittests" - }, - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ] - }, - "test": "content_unittests" - } - ] - }, - "Linux x64 Goma Canary LocalOutputCache": { - "additional_compile_targets": [ - "all" - ], - "gtest_tests": [ - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ] - }, - "test": "base_unittests" - }, - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Ubuntu-16.04" - } - ] - }, - "test": "content_unittests" - } - ] - }, "Mac Builder (dbg) Goma Canary": { "additional_compile_targets": [ "all" @@ -391,80 +312,6 @@ } ] }, - "Mac Goma Canary (clobber)": { - "additional_compile_targets": [ - "chrome" - ], - "gtest_tests": [ - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac" - } - ] - }, - "test": "base_unittests" - }, - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac" - } - ] - }, - "test": "content_unittests" - } - ] - }, - "Mac Goma Canary LocalOutputCache": { - "additional_compile_targets": [ - "chrome" - ], - "gtest_tests": [ - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac" - } - ] - }, - "test": "base_unittests" - }, - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true, - "dimension_sets": [ - { - "os": "Mac" - } - ] - }, - "test": "content_unittests" - } - ] - }, "Mojo Android": { "gtest_tests": [ { @@ -2301,33 +2148,6 @@ } ] }, - "Win Goma Canary LocalOutputCache": { - "additional_compile_targets": [ - "all" - ], - "gtest_tests": [ - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true - }, - "test": "base_unittests" - }, - { - "merge": { - "args": [], - "script": "//testing/merge_scripts/standard_gtest_merge.py" - }, - "swarming": { - "can_use_on_swarming_builders": true - }, - "test": "content_unittests" - } - ] - }, "Win cl.exe Goma Canary LocalOutputCache": { "additional_compile_targets": [ "libANGLE" @@ -2403,6 +2223,11 @@ "libANGLE" ] }, + "android-archive-dbg-goma-canary": { + "additional_compile_targets": [ + "all" + ] + }, "android-code-coverage": { "gtest_tests": [ { @@ -8103,6 +7928,80 @@ } ] }, + "linux-archive-rel-goma-canary": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-16.04" + } + ] + }, + "test": "base_unittests" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-16.04" + } + ] + }, + "test": "content_unittests" + } + ] + }, + "linux-archive-rel-goma-canary-localoutputcache": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-16.04" + } + ] + }, + "test": "base_unittests" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Ubuntu-16.04" + } + ] + }, + "test": "content_unittests" + } + ] + }, "linux-bfcache-rel": { "gtest_tests": [ { @@ -21013,6 +20912,80 @@ } ] }, + "mac-archive-rel-goma-canary": { + "additional_compile_targets": [ + "chrome" + ], + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Mac" + } + ] + }, + "test": "base_unittests" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Mac" + } + ] + }, + "test": "content_unittests" + } + ] + }, + "mac-archive-rel-goma-canary-localoutputcache": { + "additional_compile_targets": [ + "chrome" + ], + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Mac" + } + ] + }, + "test": "base_unittests" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "os": "Mac" + } + ] + }, + "test": "content_unittests" + } + ] + }, "mac-hermetic-upgrade-rel": { "additional_compile_targets": [ "all" @@ -22899,6 +22872,33 @@ } ] }, + "win32-archive-rel-goma-canary-localoutputcache": { + "additional_compile_targets": [ + "all" + ], + "gtest_tests": [ + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "base_unittests" + }, + { + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_gtest_merge.py" + }, + "swarming": { + "can_use_on_swarming_builders": true + }, + "test": "content_unittests" + } + ] + }, "win7-blink-rel-dummy": { "isolated_scripts": [ {
diff --git a/testing/buildbot/filters/bfcache.content_browsertests.filter b/testing/buildbot/filters/bfcache.content_browsertests.filter index 7c3ee33..b7aedc44 100644 --- a/testing/buildbot/filters/bfcache.content_browsertests.filter +++ b/testing/buildbot/filters/bfcache.content_browsertests.filter
@@ -1,8 +1,5 @@ # These tests currently fail when run with --enable-features=BackForwardCache. -# Terminating renderer for bad IPC message, reason 205. --NavigationControllerBrowserTest.VerifyBlockedErrorPageURL_SessionHistory - # Same-document navigation pointing to a URL that would cause a redirect if it # was reloaded. It never happen, because the document is restored directly. -NavigationControllerBrowserTest.SiteInstanceChangeOnHistoryNavigation
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl index 38beb708..fb8bfa09 100644 --- a/testing/buildbot/test_suite_exceptions.pyl +++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -19,7 +19,7 @@ 'android_webview_unittests': { 'remove_from': [ # On chromium.android, these do not need to run prior to M. - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'KitKat Phone Tester (dbg)', 'KitKat Tablet Tester', @@ -294,7 +294,7 @@ ], 'modifications': { # chromium.android - 'android-kitkat-arm-coverage-dbg': { + 'android-kitkat-arm-coverage-rel': { 'swarming': { 'shards': 12, } @@ -1051,7 +1051,7 @@ # chromium.android 'android-asan', # Don't run on trybots; waterfall is enough. - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'android-marshmallow-arm64-rel', # No capacity for tablet testers. @@ -1065,7 +1065,7 @@ # chromium.android 'android-asan', # Don't run on trybots; waterfall is enough. - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'android-marshmallow-arm64-rel', # No capacity for tablet testers. @@ -1079,7 +1079,7 @@ # chromium.android 'android-asan', # Don't run on trybots; waterfall is enough. - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'android-marshmallow-arm64-rel', # No capacity for tablet testers. @@ -1100,7 +1100,7 @@ # chromium.android 'android-asan', # Don't run on trybots; waterfall is enough. - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'android-marshmallow-arm64-rel', # No capacity for tablet testers. @@ -1113,7 +1113,7 @@ # Only run these on the phone testers for now due to capacity. 'remove_from': [ # chromium.android - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'android-marshmallow-arm64-rel', 'KitKat Tablet Tester', @@ -1261,7 +1261,7 @@ 'remove_from': [ 'android-asan', 'android-code-coverage', - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'android-marshmallow-arm64-rel', 'Android CFI', @@ -1463,7 +1463,7 @@ 'telemetry_perf_unittests': { 'modifications': { # chromium.android - 'android-kitkat-arm-coverage-dbg': { + 'android-kitkat-arm-coverage-rel': { 'args': [ '--browser=android-chromium', '--device=android', @@ -2087,7 +2087,7 @@ 'remove_from': [ # This test frequently fails on Android, https://crbug.com/824959 # chromium.android - 'android-kitkat-arm-coverage-dbg', + 'android-kitkat-arm-coverage-rel', 'android-kitkat-arm-rel', 'KitKat Phone Tester (dbg)', 'KitKat Tablet Tester',
diff --git a/testing/buildbot/tryserver.chromium.android.json b/testing/buildbot/tryserver.chromium.android.json index d5393a1..f1c9e24c 100644 --- a/testing/buildbot/tryserver.chromium.android.json +++ b/testing/buildbot/tryserver.chromium.android.json
@@ -1,7 +1,11 @@ { "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {}, "AAAAA2 See generate_buildbot_json.py to make changes": {}, - "android-kitkat-arm-coverage-dbg": { + "android-kitkat-arm-coverage-rel": { + "additional_compile_targets": [ + "cronet_test_instrumentation_apk", + "monochrome_static_initializers" + ], "gtest_tests": [ { "args": [ @@ -2810,6 +2814,28 @@ "test": "wtf_unittests" } ], + "isolated_scripts": [ + { + "isolate_coverage_data": true, + "isolate_name": "monochrome_apk_checker", + "merge": { + "args": [], + "script": "//testing/merge_scripts/standard_isolated_script_merge.py" + }, + "name": "monochrome_apk_checker", + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "device_os": "KTU84P", + "device_os_type": "userdebug", + "device_type": "hammerhead", + "os": "Android" + } + ] + } + } + ], "junit_tests": [ { "test": "android_webview_junit_tests"
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl index b088d11..d36ece90 100644 --- a/testing/buildbot/waterfalls.pyl +++ b/testing/buildbot/waterfalls.pyl
@@ -1306,11 +1306,6 @@ { 'name': 'chromium.fyi', 'machines': { - 'Android Builder (dbg) Goma Canary': { - 'additional_compile_targets': [ - 'all', - ], - }, 'Jumbo Linux x64': { 'additional_compile_targets': [ 'all', @@ -1349,28 +1344,6 @@ 'isolated_scripts': 'skia_renderer_isolated_scripts', }, }, - 'Linux x64 Goma Canary (clobber)': { - 'mixins': [ - 'linux-xenial', - ], - 'additional_compile_targets': [ - 'all', - ], - 'test_suites': { - 'gtest_tests': 'goma_gtests', - }, - }, - 'Linux x64 Goma Canary LocalOutputCache': { - 'mixins': [ - 'linux-xenial', - ], - 'additional_compile_targets': [ - 'all', - ], - 'test_suites': { - 'gtest_tests': 'goma_gtests', - }, - }, 'Mac Builder (dbg) Goma Canary': { 'additional_compile_targets': [ 'all', @@ -1396,26 +1369,6 @@ 'gtest_tests': 'goma_mac_gtests', }, }, - 'Mac Goma Canary (clobber)': { - 'additional_compile_targets': [ - # Due to disk shortage, we build 'chrome' instead of 'all'. - # See crbug.com/899425 - 'chrome', - ], - 'test_suites': { - 'gtest_tests': 'goma_mac_gtests', - }, - }, - 'Mac Goma Canary LocalOutputCache': { - 'additional_compile_targets': [ - # Due to disk shortage, we build 'chrome' instead of 'all'. - # See crbug.com/825536 - 'chrome', - ], - 'test_suites': { - 'gtest_tests': 'goma_mac_gtests', - }, - }, 'Mojo Android': { 'swarming': { 'dimension_sets': [ @@ -1522,14 +1475,6 @@ 'gtest_tests': 'goma_gtests', }, }, - 'Win Goma Canary LocalOutputCache': { - 'additional_compile_targets': [ - 'all', - ], - 'test_suites': { - 'gtest_tests': 'goma_gtests', - }, - }, 'Win cl.exe Goma Canary LocalOutputCache': { # Build only chromium's subproject using cl.exe. 'additional_compile_targets': [ @@ -1571,6 +1516,11 @@ 'libANGLE', ], }, + 'android-archive-dbg-goma-canary': { + 'additional_compile_targets': [ + 'all', + ], + }, 'android-code-coverage': { 'mixins': [ 'code-coverage', @@ -1721,6 +1671,28 @@ 'scripts': 'test_traffic_annotation_auditor_script', } }, + 'linux-archive-rel-goma-canary': { + 'mixins': [ + 'linux-xenial', + ], + 'additional_compile_targets': [ + 'all', + ], + 'test_suites': { + 'gtest_tests': 'goma_gtests', + }, + }, + 'linux-archive-rel-goma-canary-localoutputcache': { + 'mixins': [ + 'linux-xenial', + ], + 'additional_compile_targets': [ + 'all', + ], + 'test_suites': { + 'gtest_tests': 'goma_gtests', + }, + }, 'linux-bfcache-rel': { 'mixins': [ 'linux-xenial', @@ -1837,6 +1809,26 @@ 'isolated_scripts': 'wpt_web_tests', }, }, + 'mac-archive-rel-goma-canary': { + 'additional_compile_targets': [ + # Due to disk shortage, we build 'chrome' instead of 'all'. + # See crbug.com/899425 + 'chrome', + ], + 'test_suites': { + 'gtest_tests': 'goma_mac_gtests', + }, + }, + 'mac-archive-rel-goma-canary-localoutputcache': { + 'additional_compile_targets': [ + # Due to disk shortage, we build 'chrome' instead of 'all'. + # See crbug.com/825536 + 'chrome', + ], + 'test_suites': { + 'gtest_tests': 'goma_mac_gtests', + }, + }, 'mac-hermetic-upgrade-rel': { 'additional_compile_targets': [ 'all' @@ -1959,6 +1951,14 @@ 'isolated_scripts': 'chromium_webkit_isolated_scripts', }, }, + 'win32-archive-rel-goma-canary-localoutputcache': { + 'additional_compile_targets': [ + 'all', + ], + 'test_suites': { + 'gtest_tests': 'goma_gtests', + }, + }, 'win7-blink-rel-dummy': { 'swarming': { 'dimension_sets': [ @@ -4316,15 +4316,20 @@ { 'name': 'tryserver.chromium.android', 'machines': { - 'android-kitkat-arm-coverage-dbg': { + 'android-kitkat-arm-coverage-rel': { 'mixins': [ 'code-coverage', 'kitkat', 'hammerhead', ], + 'additional_compile_targets': [ + 'cronet_test_instrumentation_apk', + 'monochrome_static_initializers', + ], 'test_suites': { 'gtest_tests': 'chromium_android_gtests', 'junit_tests': 'chromium_junit_tests', + 'isolated_scripts': 'monochrome_apk_checker_isolated_script', }, 'os_type': 'android', },
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc index 010024c..9679fcd9 100644 --- a/third_party/blink/common/features.cc +++ b/third_party/blink/common/features.cc
@@ -63,11 +63,6 @@ const base::Feature kJankTrackingSweepLine{"JankTrackingSweepLine", base::FEATURE_DISABLED_BY_DEFAULT}; -// Enable a new compositing mode called BlinkGenPropertyTrees where Blink -// generates the compositor property trees. See: https://crbug.com/836884. -const base::Feature kBlinkGenPropertyTrees{"BlinkGenPropertyTrees", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Enable a new CSS property called backdrop-filter. const base::Feature kCSSBackdropFilter{"CSSBackdropFilter", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/third_party/blink/public/common/features.h b/third_party/blink/public/common/features.h index 3605f11..8a6e47a8 100644 --- a/third_party/blink/public/common/features.h +++ b/third_party/blink/public/common/features.h
@@ -28,7 +28,6 @@ BLINK_COMMON_EXPORT extern const base::Feature kFreezeUserAgent; BLINK_COMMON_EXPORT extern const base::Feature kImplicitRootScroller; BLINK_COMMON_EXPORT extern const base::Feature kJankTrackingSweepLine; -BLINK_COMMON_EXPORT extern const base::Feature kBlinkGenPropertyTrees; BLINK_COMMON_EXPORT extern const base::Feature kCSSBackdropFilter; BLINK_COMMON_EXPORT extern const base::Feature kDisplayLocking; BLINK_COMMON_EXPORT extern const base::Feature kFastBorderRadius;
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom index af4ac6e..decc41a4 100644 --- a/third_party/blink/public/mojom/web_feature/web_feature.mojom +++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2377,6 +2377,8 @@ kCSSValueOverflowOverlay = 2995, kRequestedFileSystemTemporary = 2996, kRequestedFileSystemPersistent = 2997, + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop = 2998, + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive = 2999, // Add new features immediately above this line. Don't change assigned // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc index 32925f20..c0ec993c 100644 --- a/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc +++ b/third_party/blink/renderer/bindings/core/v8/local_window_proxy.cc
@@ -412,13 +412,6 @@ return; } - // Append the agent cluster id to the generated token to prevent - // access from two contexts that have the same security origin but are - // in different agent clusters. - token = - token + - GetFrame()->GetDocument()->GetAgent()->cluster_id().ToString().c_str(); - if (world_->IsIsolatedWorld()) { const SecurityOrigin* frame_security_origin = GetFrame()->GetDocument()->GetSecurityOrigin();
diff --git a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py index 8fc3a77..117fe3af 100644 --- a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py +++ b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.py
@@ -10,8 +10,8 @@ """ import optparse +import sys -import utilities import web_idl @@ -30,16 +30,25 @@ def main(): options, filepaths = parse_options() - # Incomplete IDL compiler produces a lot of errors, which break trybots. - # So, we ignore all the errors for the time being. - # TODO(bindings-team): Replace |report_error| with sys.exit once IDL - # compiler completes. - report_error = lambda message: None + was_error_reported = [False] + + def report_error(message): + # Incomplete IDL compiler produces a lot of errors, which break trybots. + # So, we ignore all the errors for the time being. + # TODO(bindings-team): Remove the following lines and enable the error + # report. + if True: # pylint: disable=using-constant-test + return + was_error_reported[0] = True + sys.stderr.writelines([message, '\n']) database = web_idl.build_database(filepaths=filepaths, report_error=report_error) - utilities.write_pickle_file(options.output, database) + if was_error_reported[0]: + sys.exit('Aborted due to error.') + + database.write_to_file(options.output) if __name__ == '__main__':
diff --git a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps index d0168c2..6dfaa231 100644 --- a/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps +++ b/third_party/blink/renderer/bindings/scripts/build_web_idl_database.pydeps
@@ -3,7 +3,6 @@ ../../build/scripts/blinkbuild/__init__.py ../../build/scripts/blinkbuild/name_style_converter.py build_web_idl_database.py -utilities.py web_idl/__init__.py web_idl/argument.py web_idl/ast_group.py @@ -18,6 +17,7 @@ web_idl/enumeration.py web_idl/exposure.py web_idl/extended_attribute.py +web_idl/file_io.py web_idl/function_like.py web_idl/identifier_ir_map.py web_idl/idl_compiler.py
diff --git a/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps b/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps index 92f5d460..04f268b7 100644 --- a/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps +++ b/third_party/blink/renderer/bindings/scripts/collect_idl_files.pydeps
@@ -27,6 +27,7 @@ web_idl/enumeration.py web_idl/exposure.py web_idl/extended_attribute.py +web_idl/file_io.py web_idl/function_like.py web_idl/identifier_ir_map.py web_idl/idl_compiler.py
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/ast_group.py b/third_party/blink/renderer/bindings/scripts/web_idl/ast_group.py index d2f05749..b6d8384 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/ast_group.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/ast_group.py
@@ -2,8 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import pickle - +from . import file_io from .composition_parts import Component @@ -20,14 +19,12 @@ @staticmethod def read_from_file(filepath): - with open(filepath, 'r') as pickle_file: - ast_group = pickle.load(pickle_file) + ast_group = file_io.read_pickle_file(filepath) assert isinstance(ast_group, AstGroup) return ast_group def write_to_file(self, filepath): - with open(filepath, 'w') as pickle_file: - pickle.dump(self, pickle_file) + return file_io.write_pickle_file_if_changed(filepath, self) def add_ast_node(self, node): assert node.GetClass() == 'File', (
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/database.py b/third_party/blink/renderer/bindings/scripts/web_idl/database.py index 0823095..0a741db 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/database.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/database.py
@@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from . import file_io from .typedef import Typedef from .union import Union from .user_defined_type import UserDefinedType @@ -87,6 +88,15 @@ assert isinstance(database_body, DatabaseBody) self._impl = database_body + @staticmethod + def read_from_file(filepath): + database = file_io.read_pickle_file(filepath) + assert isinstance(database, Database) + return database + + def write_to_file(self, filepath): + return file_io.write_pickle_file_if_changed(filepath, self) + def find(self, identifier): """ Returns the IDL definition specified with |identifier|. Raises KeyError
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py b/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py new file mode 100644 index 0000000..9136a41a3 --- /dev/null +++ b/third_party/blink/renderer/bindings/scripts/web_idl/file_io.py
@@ -0,0 +1,43 @@ +# 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 os +import pickle + + +def read_pickle_file(filepath): + """ + Reads the content of the file as a pickled object. + """ + with open(filepath, 'r') as file_obj: + return pickle.load(file_obj) + + +def write_pickle_file_if_changed(filepath, obj): + """ + Writes the given object out to |filepath| if the content changed. + + Returns True if the object is written to the file, and False if skipped. + """ + return write_to_file_if_changed(filepath, pickle.dumps(obj)) + + +def write_to_file_if_changed(filepath, contents): + """ + Writes the given contents out to |filepath| if the contents changed. + + Returns True if the data is written to the file, and False if skipped. + """ + try: + with open(filepath, 'r') as file_obj: + old_contents = file_obj.read() + except (OSError, EnvironmentError): + pass + else: + if contents == old_contents: + return False + os.remove(filepath) + with open(filepath, 'w') as file_obj: + file_obj.write(contents) + return True
diff --git a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py index 0616ac2..fdaeabbb 100644 --- a/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py +++ b/third_party/blink/renderer/bindings/scripts/web_idl/idl_compiler.py
@@ -170,7 +170,7 @@ if obj.inherited is None: return [obj] return [obj] + create_inheritance_stack( - table.get(obj.inherited.identifier, None), table) + table[obj.inherited.identifier], table) old_interfaces = self._ir_map.find_by_kind( IdentifierIRMap.IR.Kind.INTERFACE)
diff --git a/third_party/blink/renderer/core/BUILD.gn b/third_party/blink/renderer/core/BUILD.gn index b0e52ef8..6fe873d 100644 --- a/third_party/blink/renderer/core/BUILD.gn +++ b/third_party/blink/renderer/core/BUILD.gn
@@ -29,9 +29,6 @@ # Config for code that builds as part of core. config("config") { defines = [ "BLINK_CORE_IMPLEMENTATION=1" ] - if (blink_animation_use_time_delta) { - defines += [ "BLINK_ANIMATION_USE_TIME_DELTA" ] - } if (is_android && notouch_build) { defines += [ "ENABLE_TOUCHLESS_UASTYLE_THEME" ] } @@ -105,6 +102,7 @@ "//skia", "//third_party/angle:translator", "//third_party/blink/public/mojom:mojom_broadcastchannel_bindings_blink", + "//third_party/blink/renderer/core/animation:buildflags", "//third_party/blink/renderer/core/inspector:generated", "//third_party/blink/renderer/core/probe:generated", "//third_party/blink/renderer/platform", @@ -1322,6 +1320,7 @@ "layout/geometry/physical_rect_test.cc", "layout/geometry/physical_size_test.cc", "layout/grid_test.cc", + "layout/hit_testing_test.cc", "layout/layout_block_test.cc", "layout/layout_box_model_object_test.cc", "layout/layout_box_test.cc", @@ -1614,10 +1613,6 @@ if (use_aura) { sources += [ "scroll/scrollbar_theme_aura_test.cc" ] } - - if (blink_animation_use_time_delta) { - defines = [ "BLINK_ANIMATION_USE_TIME_DELTA" ] - } } jumbo_source_set("perf_tests") {
diff --git a/third_party/blink/renderer/core/animation/BUILD.gn b/third_party/blink/renderer/core/animation/BUILD.gn index 13544228b..43fe6431 100644 --- a/third_party/blink/renderer/core/animation/BUILD.gn +++ b/third_party/blink/renderer/core/animation/BUILD.gn
@@ -2,11 +2,24 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/buildflag_header.gni") import("//third_party/blink/renderer/core/core.gni") +declare_args() { + # Use base::TimeDelta to represent time in renderer/core/animations. See + # http://crbug.com/737867 + blink_animation_use_time_delta = false +} + +buildflag_header("buildflags") { + header = "buildflags.h" + header_dir = "third_party/blink/renderer/core/animation" + + flags = [ "BLINK_ANIMATION_USE_TIME_DELTA=$blink_animation_use_time_delta" ] +} + blink_core_sources("animation") { split_count = 5 - sources = [ "animatable.cc", "animatable.h", @@ -248,6 +261,10 @@ "worklet_animation_controller.cc", "worklet_animation_controller.h", ] + + deps = [ + ":buildflags", + ] } blink_core_tests("unit_tests") {
diff --git a/third_party/blink/renderer/core/animation/animation_time_delta.cc b/third_party/blink/renderer/core/animation/animation_time_delta.cc index a1be720f..a9f0efd4 100644 --- a/third_party/blink/renderer/core/animation/animation_time_delta.cc +++ b/third_party/blink/renderer/core/animation/animation_time_delta.cc
@@ -6,7 +6,7 @@ namespace blink { -#if !defined(BLINK_ANIMATION_USE_TIME_DELTA) +#if !BUILDFLAG(BLINK_ANIMATION_USE_TIME_DELTA) // Comparison operators on AnimationTimeDelta. bool CORE_EXPORT operator==(const AnimationTimeDelta& lhs, const AnimationTimeDelta& rhs) {
diff --git a/third_party/blink/renderer/core/animation/animation_time_delta.h b/third_party/blink/renderer/core/animation/animation_time_delta.h index ccd3d93..de9f636c 100644 --- a/third_party/blink/renderer/core/animation/animation_time_delta.h +++ b/third_party/blink/renderer/core/animation/animation_time_delta.h
@@ -5,16 +5,13 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_ANIMATION_TIME_DELTA_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_ANIMATION_TIME_DELTA_H_ +#include "third_party/blink/renderer/core/animation/buildflags.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include <limits> #include <ostream> -#if defined(BLINK_ANIMATION_USE_TIME_DELTA) - -#endif - namespace blink { // AnimationTimeDelta exists to ease the transition of Blink animations from @@ -27,7 +24,7 @@ // double-precision. The second mode uses base::TimeDelta to represent time // instead. -#if !defined(BLINK_ANIMATION_USE_TIME_DELTA) +#if !BUILDFLAG(BLINK_ANIMATION_USE_TIME_DELTA) // The double-based version of AnimationTimeDelta. Internally, time is stored as // double-precision seconds. @@ -105,7 +102,7 @@ CORE_EXPORT std::ostream& operator<<(std::ostream& os, const AnimationTimeDelta& time); -#else // !defined(BLINK_ANIMATION_USE_TIME_DELTA) +#else // !BUILDFLAG(BLINK_ANIMATION_USE_TIME_DELTA) // When compiling in TimeDelta-based mode, AnimationTimeDelta is equivalent to // base::TimeDelta.
diff --git a/third_party/blink/renderer/core/animation/css_transform_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_transform_interpolation_type.cc index 0c1fee4..e5f11ee 100644 --- a/third_party/blink/renderer/core/animation/css_transform_interpolation_type.cc +++ b/third_party/blink/renderer/core/animation/css_transform_interpolation_type.cc
@@ -24,8 +24,11 @@ public: static scoped_refptr<CSSTransformNonInterpolableValue> Create( TransformOperations&& transform) { + const bool is_single = true; + const bool is_additive = false; return base::AdoptRef(new CSSTransformNonInterpolableValue( - true, std::move(transform), EmptyTransformOperations(), false, false)); + is_single, std::move(transform), EmptyTransformOperations(), + is_additive, is_additive)); } static scoped_refptr<CSSTransformNonInterpolableValue> CreateAdditive( @@ -52,7 +55,10 @@ scoped_refptr<CSSTransformNonInterpolableValue> Composite( const CSSTransformNonInterpolableValue& other, double other_progress) const { + DCHECK(is_single_); DCHECK(!IsAdditive()); + + // This is the case where we have no B, so the equation is U + A. if (other.is_single_) { DCHECK_EQ(other_progress, 0); DCHECK(other.IsAdditive()); @@ -61,6 +67,10 @@ return Create(std::move(result)); } + // Otherwise, we must compute (U + A)(1 - f) + (U + B)f - where U is only + // included if the keyframe is additive. This requires pre-pending the + // underlying ops to the necessary sides and then performing the + // interpolation. DCHECK(other.is_start_additive_ || other.is_end_additive_); TransformOperations start; start.Operations() = other.is_start_additive_ @@ -81,6 +91,8 @@ return end_.Blend(start_, progress); } + bool IsSingle() const { return is_single_; } + DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); private: @@ -152,6 +164,34 @@ const TransformOperations inherited_transform_; }; +// Performs interpolation for the UnderlyingValueOwner, if necessary. This +// requires us to: +// +// i. Compute the interpolation for the CSSTransformNonInterpolableValue. +// ii. Reset the underlying_value_owner's interpolable_value (which is the +// progress) to 0. This is necessary to avoid double-interpolating in +// ApplyStandardPropertyValue. +void InterpolateUnderlyingValueOwnerIfNecessary( + UnderlyingValueOwner& underlying_value_owner) { + const CSSTransformNonInterpolableValue& underlying_non_interpolable_value = + ToCSSTransformNonInterpolableValue( + *underlying_value_owner.Value().non_interpolable_value); + // If the UnderlyingValueOwner is already single, it is either based on the + // underlying CSS style itself, or has already been interpolated. + if (underlying_non_interpolable_value.IsSingle()) + return; + + double underlying_progress = + ToInterpolableNumber(*underlying_value_owner.Value().interpolable_value) + .Value(); + underlying_value_owner.SetInterpolableValue( + std::make_unique<InterpolableNumber>(0)); + underlying_value_owner.SetNonInterpolableValue( + CSSTransformNonInterpolableValue::Create( + underlying_non_interpolable_value.GetInterpolatedTransform( + underlying_progress))); +} + } // namespace InterpolationValue CSSTransformInterpolationType::MaybeConvertNeutral( @@ -251,15 +291,23 @@ double underlying_fraction, const InterpolationValue& value, double interpolation_fraction) const { + // If the first InvalidatableInterpolation in the stack doesn't depend on an + // underlying value, it becomes the underlying value, U. However at this point + // U has not yet been interpolated (as interpolation for + // CSSTransformInterpolationType only happens in either Composite or + // ApplyStandardPropertyValue), and so we have to do it here. + InterpolateUnderlyingValueOwnerIfNecessary(underlying_value_owner); + + // Now that U has been resolved, do the actual compositing. const CSSTransformNonInterpolableValue& underlying_non_interpolable_value = ToCSSTransformNonInterpolableValue( - *underlying_value_owner.Value().non_interpolable_value); + *underlying_value_owner.GetNonInterpolableValue()); const CSSTransformNonInterpolableValue& non_interpolable_value = ToCSSTransformNonInterpolableValue(*value.non_interpolable_value); double progress = ToInterpolableNumber(*value.interpolable_value).Value(); - underlying_value_owner.MutableValue().non_interpolable_value = + underlying_value_owner.SetNonInterpolableValue( underlying_non_interpolable_value.Composite(non_interpolable_value, - progress); + progress)); } void CSSTransformInterpolationType::ApplyStandardPropertyValue(
diff --git a/third_party/blink/renderer/core/animation/document_timeline.cc b/third_party/blink/renderer/core/animation/document_timeline.cc index 57efc9f..44c6bf1 100644 --- a/third_party/blink/renderer/core/animation/document_timeline.cc +++ b/third_party/blink/renderer/core/animation/document_timeline.cc
@@ -196,15 +196,16 @@ if (time_to_next_effect < kMinimumDelay) { timing_->ServiceOnNextFrame(); } else if (time_to_next_effect != std::numeric_limits<double>::infinity()) { - timing_->WakeAfter(time_to_next_effect - kMinimumDelay); + timing_->WakeAfter( + base::TimeDelta::FromSecondsD(time_to_next_effect - kMinimumDelay)); } } -void DocumentTimeline::DocumentTimelineTiming::WakeAfter(double duration) { - base::TimeDelta duration_delta = base::TimeDelta::FromSecondsD(duration); - if (timer_.IsActive() && timer_.NextFireInterval() < duration_delta) +void DocumentTimeline::DocumentTimelineTiming::WakeAfter( + base::TimeDelta duration) { + if (timer_.IsActive() && timer_.NextFireInterval() < duration) return; - timer_.StartOneShot(duration_delta, FROM_HERE); + timer_.StartOneShot(duration, FROM_HERE); } void DocumentTimeline::DocumentTimelineTiming::ServiceOnNextFrame() {
diff --git a/third_party/blink/renderer/core/animation/document_timeline.h b/third_party/blink/renderer/core/animation/document_timeline.h index 454d546..d14d5cb 100644 --- a/third_party/blink/renderer/core/animation/document_timeline.h +++ b/third_party/blink/renderer/core/animation/document_timeline.h
@@ -62,7 +62,7 @@ class PlatformTiming : public GarbageCollectedFinalized<PlatformTiming> { public: // Calls DocumentTimeline's wake() method after duration seconds. - virtual void WakeAfter(double duration) = 0; + virtual void WakeAfter(base::TimeDelta duration) = 0; virtual void ServiceOnNextFrame() = 0; virtual ~PlatformTiming() = default; virtual void Trace(blink::Visitor* visitor) {} @@ -166,7 +166,7 @@ DCHECK(timeline_); } - void WakeAfter(double duration) override; + void WakeAfter(base::TimeDelta duration) override; void ServiceOnNextFrame() override; void TimerFired(TimerBase*) { timeline_->Wake(); }
diff --git a/third_party/blink/renderer/core/animation/document_timeline_test.cc b/third_party/blink/renderer/core/animation/document_timeline_test.cc index ca3fc53..73ead918 100644 --- a/third_party/blink/renderer/core/animation/document_timeline_test.cc +++ b/third_party/blink/renderer/core/animation/document_timeline_test.cc
@@ -57,7 +57,7 @@ class MockPlatformTiming : public DocumentTimeline::PlatformTiming { public: - MOCK_METHOD1(WakeAfter, void(double)); + MOCK_METHOD1(WakeAfter, void(base::TimeDelta)); MOCK_METHOD0(ServiceOnNextFrame, void()); void Trace(blink::Visitor* visitor) override { @@ -356,11 +356,13 @@ // TODO: Put the animation startTime in the future when we add the capability // to change animation startTime - EXPECT_CALL(*platform_timing, WakeAfter(timing.start_delay - MinimumDelay())); + EXPECT_CALL(*platform_timing, WakeAfter(base::TimeDelta::FromSecondsD( + timing.start_delay - MinimumDelay()))); UpdateClockAndService(0); EXPECT_CALL(*platform_timing, - WakeAfter(timing.start_delay - MinimumDelay() - 1.5)); + WakeAfter(base::TimeDelta::FromSecondsD(timing.start_delay - + MinimumDelay() - 1.5))); UpdateClockAndService(1500); EXPECT_CALL(*platform_timing, ServiceOnNextFrame());
diff --git a/third_party/blink/renderer/core/core.gni b/third_party/blink/renderer/core/core.gni index cd2857b..97f02c4 100644 --- a/third_party/blink/renderer/core/core.gni +++ b/third_party/blink/renderer/core/core.gni
@@ -151,9 +151,3 @@ "//third_party/blink/renderer:inside_blink", ] } - -declare_args() { - # Use base::TimeDelta to represent time in renderer/core/animations. See - # http://crbug.com/737867 - blink_animation_use_time_delta = false -}
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc index 6da0605..9120c8d 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.cc +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.cc
@@ -2208,6 +2208,22 @@ return list; } +CSSValuePair* ComputedStyleUtils::ValuesForGapShorthand( + const StylePropertyShorthand& shorthand, + const ComputedStyle& style, + const LayoutObject* layout_object, + bool allow_visited_style) { + const CSSValue* row_gap_value = + shorthand.properties()[0]->CSSValueFromComputedStyle(style, layout_object, + allow_visited_style); + const CSSValue* column_gap_value = + shorthand.properties()[1]->CSSValueFromComputedStyle(style, layout_object, + allow_visited_style); + + return MakeGarbageCollected<CSSValuePair>(row_gap_value, column_gap_value, + CSSValuePair::kDropIdenticalValues); +} + CSSValueList* ComputedStyleUtils::ValuesForGridShorthand( const StylePropertyShorthand& shorthand, const ComputedStyle& style,
diff --git a/third_party/blink/renderer/core/css/properties/computed_style_utils.h b/third_party/blink/renderer/core/css/properties/computed_style_utils.h index d28094a..83f487f7 100644 --- a/third_party/blink/renderer/core/css/properties/computed_style_utils.h +++ b/third_party/blink/renderer/core/css/properties/computed_style_utils.h
@@ -178,6 +178,10 @@ const ComputedStyle&, const LayoutObject*, bool allow_visited_style); + static CSSValuePair* ValuesForGapShorthand(const StylePropertyShorthand&, + const ComputedStyle&, + const LayoutObject*, + bool allow_visited_style); static CSSValueList* ValuesForGridShorthand(const StylePropertyShorthand&, const ComputedStyle&, const LayoutObject*,
diff --git a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc index 81707c6..988c6e97 100644 --- a/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/shorthands/shorthands_custom.cc
@@ -1374,7 +1374,7 @@ const SVGComputedStyle&, const LayoutObject* layout_object, bool allow_visited_style) const { - return ComputedStyleUtils::ValuesForShorthandProperty( + return ComputedStyleUtils::ValuesForGapShorthand( gapShorthand(), style, layout_object, allow_visited_style); }
diff --git a/third_party/blink/renderer/core/css/style_property_serializer.cc b/third_party/blink/renderer/core/css/style_property_serializer.cc index 87baec6e..70b8bb6 100644 --- a/third_party/blink/renderer/core/css/style_property_serializer.cc +++ b/third_party/blink/renderer/core/css/style_property_serializer.cc
@@ -494,7 +494,7 @@ case CSSPropertyID::kGridArea: return GetShorthandValue(gridAreaShorthand(), " / "); case CSSPropertyID::kGap: - return GetShorthandValue(gapShorthand()); + return Get2Values(gapShorthand()); case CSSPropertyID::kInset: return Get4Values(insetShorthand()); case CSSPropertyID::kInsetBlock:
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index f2679911..883078d 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -807,6 +807,27 @@ .GetSecurityOrigin() ->IsolatedCopy(); } + + if (initializer.HasSecurityContext()) { + if (Settings* settings = initializer.GetSettings()) { + if (!settings->GetWebSecurityEnabled()) { + // Web security is turned off. We should let this document access + // every other document. This is used primary by testing harnesses for + // web sites. + security_origin_->GrantUniversalAccess(); + } else if (security_origin_->IsLocal()) { + if (settings->GetAllowUniversalAccessFromFileURLs()) { + // Some clients want local URLs to have universal access, but that + // setting is dangerous for other clients. + security_origin_->GrantUniversalAccess(); + } else if (!settings->GetAllowFileAccessFromFileURLs()) { + // Some clients do not want local URLs to have access to other local + // URLs. + security_origin_->BlockLocalAccessFromLocalOrigin(); + } + } + } + } } void InitializeFeaturePolicy(const DocumentInit& initializer, @@ -928,6 +949,10 @@ agent_ = MakeGarbageCollected<WindowAgent>( V8PerIsolateData::MainThreadIsolate()); } + + // Derive possibly a new security origin that contains the cluster id. + security_origin_ = + security_origin_->GetOriginForAgentCluster(agent_->cluster_id()); } bool IsPagePopupRunningInWebTest(LocalFrame* frame) { @@ -6890,25 +6915,6 @@ SetAddressSpace(network::mojom::IPAddressSpace::kPublic); } - if (Settings* settings = initializer.GetSettings()) { - if (!settings->GetWebSecurityEnabled()) { - // Web security is turned off. We should let this document access every - // other document. This is used primary by testing harnesses for web - // sites. - GetMutableSecurityOrigin()->GrantUniversalAccess(); - } else if (GetSecurityOrigin()->IsLocal()) { - if (settings->GetAllowUniversalAccessFromFileURLs()) { - // Some clients want local URLs to have universal access, but that - // setting is dangerous for other clients. - GetMutableSecurityOrigin()->GrantUniversalAccess(); - } else if (!settings->GetAllowFileAccessFromFileURLs()) { - // Some clients do not want local URLs to have access to other local - // URLs. - GetMutableSecurityOrigin()->BlockLocalAccessFromLocalOrigin(); - } - } - } - if (GetSecurityOrigin()->IsOpaque() && SecurityOrigin::Create(url_)->IsPotentiallyTrustworthy()) GetMutableSecurityOrigin()->SetOpaqueOriginIsPotentiallyTrustworthy(true);
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc index 59ddfc2..0f5ec42 100644 --- a/third_party/blink/renderer/core/dom/element.cc +++ b/third_party/blink/renderer/core/dom/element.cc
@@ -355,6 +355,31 @@ return false; } +bool HasLeftwardDirection(const Element& element) { + auto* style = element.GetComputedStyle(); + if (!style) + return false; + + WritingMode writing_mode = style->GetWritingMode(); + bool is_rtl = !style->IsLeftToRightDirection(); + return (writing_mode == WritingMode::kHorizontalTb && is_rtl) || + writing_mode == WritingMode::kVerticalRl || + writing_mode == WritingMode::kSidewaysRl; +} + +bool HasUpwardDirection(const Element& element) { + auto* style = element.GetComputedStyle(); + if (!style) + return false; + + WritingMode writing_mode = style->GetWritingMode(); + bool is_rtl = !style->IsLeftToRightDirection(); + return (is_rtl && (writing_mode == WritingMode::kVerticalRl || + writing_mode == WritingMode::kVerticalLr || + writing_mode == WritingMode::kSidewaysRl)) || + (!is_rtl && writing_mode == WritingMode::kSidewaysLr); +} + } // namespace Element* Element::Create(const QualifiedName& tag_name, Document* document) { @@ -994,6 +1019,14 @@ if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) { DCHECK(GetLayoutBox()); + + if (HasLeftwardDirection(*this)) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop); + } + return AdjustForAbsoluteZoom::AdjustScroll( scrollable_area->ScrollPosition().X(), *GetLayoutBox()); } @@ -1015,6 +1048,14 @@ if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) { DCHECK(GetLayoutBox()); + + if (HasUpwardDirection(*this)) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop); + } + return AdjustForAbsoluteZoom::AdjustScroll( scrollable_area->ScrollPosition().Y(), *GetLayoutBox()); } @@ -1039,6 +1080,20 @@ } else if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) { LayoutBox* box = GetLayoutBox(); DCHECK(box); + + if (HasLeftwardDirection(*this)) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop); + if (new_left > 0) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive); + } + } + FloatPoint end_point(new_left * box->Style()->EffectiveZoom(), scrollable_area->ScrollPosition().Y()); std::unique_ptr<cc::SnapSelectionStrategy> strategy = @@ -1073,6 +1128,20 @@ } else if (PaintLayerScrollableArea* scrollable_area = GetScrollableArea()) { LayoutBox* box = GetLayoutBox(); DCHECK(box); + + if (HasUpwardDirection(*this)) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop); + if (new_top > 0) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive); + } + } + FloatPoint end_point(scrollable_area->ScrollPosition().X(), new_top * box->Style()->EffectiveZoom()); std::unique_ptr<cc::SnapSelectionStrategy> strategy = @@ -1222,11 +1291,37 @@ FloatPoint new_position(scrollable_area->ScrollPosition().X(), scrollable_area->ScrollPosition().Y()); if (scroll_to_options->hasLeft()) { + if (HasLeftwardDirection(*this)) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop); + if (scroll_to_options->left() > 0) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive); + } + } + new_position.SetX( ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->left()) * box->Style()->EffectiveZoom()); } if (scroll_to_options->hasTop()) { + if (HasUpwardDirection(*this)) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop); + if (scroll_to_options->top() > 0) { + UseCounter::Count( + GetDocument(), + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive); + } + } + new_position.SetY( ScrollableArea::NormalizeNonFiniteScroll(scroll_to_options->top()) * box->Style()->EffectiveZoom());
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc index 40b2b5b..c0fa7a4 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader.cc +++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.cc
@@ -147,10 +147,12 @@ if (!finished_loading_) { return DOMArrayBuffer::Create(ArrayBuffer::Create( - raw_data_->Data(), static_cast<unsigned>(bytes_loaded_))); + raw_data_.Data(), static_cast<unsigned>(bytes_loaded_))); } - array_buffer_result_ = DOMArrayBuffer::Create(std::move(raw_data_)); + WTF::ArrayBufferContents contents(std::move(raw_data_), + WTF::ArrayBufferContents::kNotShared); + array_buffer_result_ = DOMArrayBuffer::Create(contents); AdjustReportedMemoryUsageToV8(-1 * static_cast<int64_t>(bytes_loaded_)); raw_data_.reset(); return array_buffer_result_; @@ -170,7 +172,7 @@ // No conversion is needed. return string_result_; case kReadAsBinaryString: - SetStringResult(String(static_cast<const char*>(raw_data_->Data()), + SetStringResult(String(static_cast<const char*>(raw_data_.Data()), static_cast<size_t>(bytes_loaded_))); break; case kReadAsText: @@ -193,6 +195,17 @@ return string_result_; } +WTF::ArrayBufferContents::DataHandle FileReaderLoader::TakeDataHandle() { + if (!raw_data_ || error_code_ != FileErrorCode::kOK) + return WTF::ArrayBufferContents::DataHandle(); + + DCHECK(finished_loading_); + WTF::ArrayBufferContents::DataHandle handle = std::move(raw_data_); + AdjustReportedMemoryUsageToV8(-1 * static_cast<int64_t>(bytes_loaded_)); + raw_data_.reset(); + return handle; +} + void FileReaderLoader::SetEncoding(const String& encoding) { if (!encoding.IsEmpty()) encoding_ = WTF::TextEncoding(encoding); @@ -241,7 +254,9 @@ return; } - raw_data_ = ArrayBuffer::Create(static_cast<unsigned>(total_bytes), 1); + raw_data_ = WTF::ArrayBufferContents::CreateDataHandle( + static_cast<unsigned>(total_bytes), + WTF::ArrayBufferContents::kDontInitialize); if (!raw_data_) { Failed(FileErrorCode::kNotReadableErr, FailureType::kArrayBufferBuilderCreation); @@ -273,14 +288,14 @@ // that the BlobPtr is actually backed by a "real" blob, so to defend against // compromised renderer processes we still need to carefully validate anything // received. So return an error if we received too much data. - if (bytes_loaded_ + data_length > raw_data_->ByteLength()) { + if (bytes_loaded_ + data_length > raw_data_.DataLength()) { raw_data_.reset(); bytes_loaded_ = 0; Failed(FileErrorCode::kNotReadableErr, FailureType::kArrayBufferBuilderAppend); return; } - memcpy(static_cast<char*>(raw_data_->Data()) + bytes_loaded_, data, + memcpy(static_cast<char*>(raw_data_.Data()) + bytes_loaded_, data, data_length); bytes_loaded_ += data_length; is_raw_data_converted_ = false; @@ -292,7 +307,7 @@ void FileReaderLoader::OnFinishLoading() { if (read_type_ != kReadByClient && raw_data_) { - DCHECK_EQ(bytes_loaded_, raw_data_->ByteLength()); + DCHECK_EQ(bytes_loaded_, raw_data_.DataLength()); is_raw_data_converted_ = false; } @@ -435,7 +450,7 @@ TextResourceDecoderOptions::kPlainTextContent, encoding_.IsValid() ? encoding_ : UTF8Encoding())); } - builder.Append(decoder_->Decode(static_cast<const char*>(raw_data_->Data()), + builder.Append(decoder_->Decode(static_cast<const char*>(raw_data_.Data()), static_cast<size_t>(bytes_loaded_))); if (finished_loading_) @@ -461,7 +476,7 @@ builder.Append(";base64,"); Vector<char> out; - Base64Encode(base::make_span(static_cast<const uint8_t*>(raw_data_->Data()), + Base64Encode(base::make_span(static_cast<const uint8_t*>(raw_data_.Data()), SafeCast<unsigned>(bytes_loaded_)), out); builder.Append(out.data(), out.size());
diff --git a/third_party/blink/renderer/core/fileapi/file_reader_loader.h b/third_party/blink/renderer/core/fileapi/file_reader_loader.h index d460a3f..5bf738e 100644 --- a/third_party/blink/renderer/core/fileapi/file_reader_loader.h +++ b/third_party/blink/renderer/core/fileapi/file_reader_loader.h
@@ -44,6 +44,7 @@ #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer.h" +#include "third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h" namespace blink { @@ -85,6 +86,7 @@ DOMArrayBuffer* ArrayBufferResult(); String StringResult(); + WTF::ArrayBufferContents::DataHandle TakeDataHandle(); // Returns the total bytes received. Bytes ignored by m_rawData won't be // counted. @@ -154,7 +156,7 @@ WTF::TextEncoding encoding_; String data_type_; - scoped_refptr<ArrayBuffer> raw_data_; + WTF::ArrayBufferContents::DataHandle raw_data_; bool is_raw_data_converted_ = false; Persistent<DOMArrayBuffer> array_buffer_result_;
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc index 5b19041..3d908b6e 100644 --- a/third_party/blink/renderer/core/frame/local_frame.cc +++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -527,7 +527,7 @@ // frame must be evicted in such cases. if (RuntimeEnabledFeatures::BackForwardCacheEnabled()) { // TODO(hajimehoshi): Set the callback only when the frame is frozen by - // BackForwardCache (crbug.com/990718). + // BackForwardCache. See https://crbug.com/990718. Vector<scoped_refptr<DOMWrapperWorld>> worlds; DOMWrapperWorld::AllWorldsInCurrentThread(worlds); for (const auto& world : worlds) { @@ -549,6 +549,16 @@ void LocalFrame::DidResume() { if (GetDocument()) { + // TODO(hajimehoshi): Unset the callback only when the frame is unfrozen by + // BackForwardCache. See https://crbug.com/990718. + Vector<scoped_refptr<DOMWrapperWorld>> worlds; + DOMWrapperWorld::AllWorldsInCurrentThread(worlds); + for (const auto& world : worlds) { + ScriptState* script_state = ToScriptState(this, *world); + ScriptState::Scope scope(script_state); + script_state->GetContext()->SetAbortScriptExecution(nullptr); + } + const base::TimeTicks resume_event_start = base::TimeTicks::Now(); GetDocument()->DispatchEvent(*Event::Create(event_type_names::kResume)); const base::TimeTicks resume_event_end = base::TimeTicks::Now(); @@ -563,14 +573,6 @@ document_resource_coordinator->SetLifecycleState( resource_coordinator::mojom::LifecycleState::kRunning); } - - Vector<scoped_refptr<DOMWrapperWorld>> worlds; - DOMWrapperWorld::AllWorldsInCurrentThread(worlds); - for (const auto& world : worlds) { - ScriptState* script_state = ToScriptState(this, *world); - ScriptState::Scope scope(script_state); - script_state->GetContext()->SetAbortScriptExecution(nullptr); - } } } @@ -995,7 +997,7 @@ return true; // Navigating window.opener cross origin, without user activation. See - // crbug.com/813643. + // https://crbug.com/813643. if (Client()->Opener() == target_frame && !HasTransientUserActivation(this, false /* check_if_main_thread */) && !target_frame.GetSecurityContext()->GetSecurityOrigin()->CanAccess(
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.cc b/third_party/blink/renderer/core/frame/root_frame_viewport.cc index 37a92dbf..032ce3bf 100644 --- a/third_party/blink/renderer/core/frame/root_frame_viewport.cc +++ b/third_party/blink/renderer/core/frame/root_frame_viewport.cc
@@ -271,6 +271,10 @@ return LayoutViewport().ScrollBehaviorStyle(); } +WebColorScheme RootFrameViewport::UsedColorScheme() const { + return LayoutViewport().UsedColorScheme(); +} + ScrollOffset RootFrameViewport::ClampToUserScrollableOffset( const ScrollOffset& offset) const { ScrollOffset scroll_offset = offset;
diff --git a/third_party/blink/renderer/core/frame/root_frame_viewport.h b/third_party/blink/renderer/core/frame/root_frame_viewport.h index 46d8b5ec..4b498850 100644 --- a/third_party/blink/renderer/core/frame/root_frame_viewport.h +++ b/third_party/blink/renderer/core/frame/root_frame_viewport.h
@@ -115,6 +115,7 @@ void UpdateCompositorScrollAnimations() override; void CancelProgrammaticScrollAnimation() override; ScrollBehavior ScrollBehaviorStyle() const override; + WebColorScheme UsedColorScheme() const override; void ClearScrollableArea() override; LayoutBox* GetLayoutBox() const override; FloatQuad LocalToVisibleContentQuad(const FloatQuad&,
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc index a50445b..903494b 100644 --- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc +++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
@@ -738,9 +738,16 @@ CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId); CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit); + // The security origin received via IPC doesn't contain the agent cluster + // ID so we need to make sure it contains the cluster agent ID from + // the current document. scoped_refptr<SecurityOrigin> security_origin = - info.security_origin.Get() ? info.security_origin.Get()->IsolatedCopy() - : nullptr; + info.security_origin.Get() + ? info.security_origin.Get() + ->IsolatedCopy() + ->GetOriginForAgentCluster( + GetFrame()->GetDocument()->GetAgentClusterID()) + : nullptr; CHECK(info.content_security_policy.IsNull() || security_origin);
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc index b07ff45..9269d3b 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.cc
@@ -49,7 +49,6 @@ #include "third_party/blink/renderer/core/svg/svg_image_element.h" #include "third_party/blink/renderer/core/workers/worker_global_scope.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" -#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" #include "third_party/blink/renderer/platform/instrumentation/histogram.h" #include "third_party/blink/renderer/platform/instrumentation/use_counter.h" #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h" @@ -298,76 +297,62 @@ } void ImageBitmapFactories::ImageBitmapLoader::DidFinishLoading() { - DOMArrayBuffer* array_buffer = loader_->ArrayBufferResult(); + auto data_handle = loader_->TakeDataHandle(); loader_.reset(); - if (!array_buffer) { + if (!data_handle) { RejectPromise(kAllocationFailureImageBitmapRejectionReason); return; } - ScheduleAsyncImageBitmapDecoding(array_buffer); + ScheduleAsyncImageBitmapDecoding(std::move(data_handle)); } void ImageBitmapFactories::ImageBitmapLoader::DidFail(FileErrorCode) { RejectPromise(kUndecodableImageBitmapRejectionReason); } -void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding( - DOMArrayBuffer* array_buffer) { - DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); - scoped_refptr<base::SingleThreadTaskRunner> task_runner = - Thread::Current()->GetTaskRunner(); - worker_pool::PostTask( - FROM_HERE, - CrossThreadBindOnce( - &ImageBitmapFactories::ImageBitmapLoader::DecodeImageOnDecoderThread, - WrapCrossThreadWeakPersistent(this), std::move(task_runner), - WrapCrossThreadPersistent(array_buffer), options_->premultiplyAlpha(), - options_->colorSpaceConversion(), IsMainThread())); -} - -void ImageBitmapFactories::ImageBitmapLoader::DecodeImageOnDecoderThread( +namespace { +void DecodeImageOnDecoderThread( scoped_refptr<base::SingleThreadTaskRunner> task_runner, - DOMArrayBuffer* array_buffer, - const String& premultiply_alpha_option, - const String& color_space_conversion_option, - bool scheduled_from_main_thread) { -#if DCHECK_IS_ON() - DCHECK(!sequence_checker_.CalledOnValidSequence()); -#endif // DCHECK_IS_ON() - ImageDecoder::AlphaOption alpha_op = ImageDecoder::kAlphaPremultiplied; - if (premultiply_alpha_option == "none") - alpha_op = ImageDecoder::kAlphaNotPremultiplied; - bool ignore_color_space = false; - if (color_space_conversion_option == "none") - ignore_color_space = true; + WTF::ArrayBufferContents::DataHandle data_handle, + ImageDecoder::AlphaOption alpha_option, + ColorBehavior color_behavior, + WTF::CrossThreadOnceFunction<void(sk_sp<SkImage>)> result_callback) { const bool data_complete = true; - // As array buffer can be created from a worker thread, and that thread can be - // destroyed, there would be the possibility of a race condition here when - // creating the SkData without copy (just referencing it). To fix this issue - // we will be making it with copy if we don't come from the main thread, to - // ensure that the data will be safe in the current thread where the decoding - // is taking place. - // todo(crbug/989675) Evaluate if there is another way to fix this without - // copying the array. std::unique_ptr<ImageDecoder> decoder = ImageDecoder::Create( - SegmentReader::CreateFromSkData( - scheduled_from_main_thread - ? SkData::MakeWithoutCopy(array_buffer->Data(), - array_buffer->ByteLength()) - : SkData::MakeWithCopy(array_buffer->Data(), - array_buffer->ByteLength())), - data_complete, alpha_op, ImageDecoder::kDefaultBitDepth, - ignore_color_space ? ColorBehavior::Ignore() : ColorBehavior::Tag()); + SegmentReader::CreateFromSkData(SkData::MakeWithoutCopy( + data_handle.Data(), data_handle.DataLength())), + data_complete, alpha_option, ImageDecoder::kDefaultBitDepth, + color_behavior); sk_sp<SkImage> frame; if (decoder) { frame = ImageBitmap::GetSkImageFromDecoder(std::move(decoder)); } PostCrossThreadTask( *task_runner, FROM_HERE, - CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader:: - ResolvePromiseOnOriginalThread, - WrapCrossThreadWeakPersistent(this), - std::move(frame))); + CrossThreadBindOnce(std::move(result_callback), std::move(frame))); +} +} // namespace + +void ImageBitmapFactories::ImageBitmapLoader::ScheduleAsyncImageBitmapDecoding( + WTF::ArrayBufferContents::DataHandle data_handle) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + scoped_refptr<base::SingleThreadTaskRunner> task_runner = + Thread::Current()->GetTaskRunner(); + ImageDecoder::AlphaOption alpha_option = + options_->premultiplyAlpha() != "none" + ? ImageDecoder::AlphaOption::kAlphaPremultiplied + : ImageDecoder::AlphaOption::kAlphaNotPremultiplied; + ColorBehavior color_behavior = options_->colorSpaceConversion() == "none" + ? ColorBehavior::Ignore() + : ColorBehavior::Tag(); + worker_pool::PostTask( + FROM_HERE, + CrossThreadBindOnce( + DecodeImageOnDecoderThread, std::move(task_runner), + std::move(data_handle), alpha_option, color_behavior, + CrossThreadBindOnce(&ImageBitmapFactories::ImageBitmapLoader:: + ResolvePromiseOnOriginalThread, + WrapCrossThreadWeakPersistent(this)))); } void ImageBitmapFactories::ImageBitmapLoader::ResolvePromiseOnOriginalThread(
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h index e239bdd..465ccbfa 100644 --- a/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h +++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap_factories.h
@@ -47,6 +47,7 @@ #include "third_party/blink/renderer/platform/bindings/name_client.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/geometry/int_rect.h" +#include "third_party/blink/renderer/platform/image-decoders/image_decoder.h" #include "third_party/blink/renderer/platform/supplementable.h" #include "third_party/skia/include/core/SkRefCnt.h" @@ -138,12 +139,7 @@ void RejectPromise(ImageBitmapRejectionReason); - void ScheduleAsyncImageBitmapDecoding(DOMArrayBuffer*); - void DecodeImageOnDecoderThread(scoped_refptr<base::SingleThreadTaskRunner>, - DOMArrayBuffer*, - const String& premultiply_alpha_option, - const String& color_space_conversion_option, - bool scheduled_from_main_thread); + void ScheduleAsyncImageBitmapDecoding(WTF::ArrayBufferContents::DataHandle); void ResolvePromiseOnOriginalThread(sk_sp<SkImage>); // ContextLifecycleObserver
diff --git a/third_party/blink/renderer/core/layout/hit_testing_test.cc b/third_party/blink/renderer/core/layout/hit_testing_test.cc new file mode 100644 index 0000000..8927df5b --- /dev/null +++ b/third_party/blink/renderer/core/layout/hit_testing_test.cc
@@ -0,0 +1,79 @@ +// 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/core/css/css_property_names.h" +#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" + +namespace blink { + +class HitTestingTest : public RenderingTest {}; + +TEST_F(HitTestingTest, OcclusionHitTest) { + SetBodyInnerHTML(R"HTML( + <style> + div { + width: 100px; + height: 100px; + } + </style> + + <div id=target></div> + <div id=occluder></div> + )HTML"); + + Element* target = GetDocument().getElementById("target"); + Element* occluder = GetDocument().getElementById("occluder"); + HitTestResult result = target->GetLayoutObject()->HitTestForOcclusion(); + EXPECT_EQ(result.InnerNode(), target); + + occluder->SetInlineStyleProperty(CSSPropertyID::kMarginTop, "-10px"); + UpdateAllLifecyclePhasesForTest(); + result = target->GetLayoutObject()->HitTestForOcclusion(); + EXPECT_EQ(result.InnerNode(), occluder); +} + +TEST_F(HitTestingTest, OcclusionHitTestWithClipPath) { + SetBodyInnerHTML(R"HTML( + <style> + div { + width: 100px; + height: 100px; + } + #occluder { + clip-path: url(#clip); + } + </style> + + <svg viewBox="0 0 100 100" width=0> + <clipPath id="clip"> + <circle cx="50" cy="50" r="45" stroke="none" /> + </clipPath> + </svg> + + <div id=target></div> + <div id=occluder></div> + )HTML"); + + Element* target = GetDocument().getElementById("target"); + Element* occluder = GetDocument().getElementById("occluder"); + + // target and occluder don't overlap, no occlusion. + HitTestResult result = target->GetLayoutObject()->HitTestForOcclusion(); + EXPECT_EQ(result.InnerNode(), target); + + // target and occluder layout rects overlap, but the overlapping area of the + // occluder is clipped out, so no occlusion. + occluder->SetInlineStyleProperty(CSSPropertyID::kMarginTop, "-4px"); + UpdateAllLifecyclePhasesForTest(); + result = target->GetLayoutObject()->HitTestForOcclusion(); + EXPECT_EQ(result.InnerNode(), target); + + // target and clipped area of occluder overlap, so there is occlusion. + occluder->SetInlineStyleProperty(CSSPropertyID::kMarginTop, "-6px"); + UpdateAllLifecyclePhasesForTest(); + result = target->GetLayoutObject()->HitTestForOcclusion(); + EXPECT_EQ(result.InnerNode(), occluder); +} + +} // namespace blink
diff --git a/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc b/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc index 2870a4aa..b63377f 100644 --- a/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc +++ b/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc
@@ -117,7 +117,8 @@ void LayoutScrollbarTheme::PaintScrollCorner( GraphicsContext& context, const DisplayItemClient& display_item_client, - const IntRect& corner_rect) { + const IntRect& corner_rect, + WebColorScheme color_scheme) { if (DrawingRecorder::UseCachedDrawingIfPossible( context, display_item_client, DisplayItem::kScrollbarCorner)) return;
diff --git a/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h b/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h index 320bb7a7..1e713d1 100644 --- a/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h +++ b/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h
@@ -47,7 +47,8 @@ void PaintScrollCorner(GraphicsContext&, const DisplayItemClient&, - const IntRect& corner_rect) override; + const IntRect& corner_rect, + WebColorScheme color_scheme) override; bool ShouldCenterOnThumb(const Scrollbar& scrollbar, const WebMouseEvent& event) override {
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc index 5ecc148..0f6d2ad 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -43,12 +43,11 @@ NGInlineNode inline_node(block_flow); LogicalSize size(LayoutUnit(50), LayoutUnit(20)); - NGConstraintSpace constraint_space = - NGConstraintSpaceBuilder( - WritingMode::kHorizontalTb, WritingMode::kHorizontalTb, - /* is_new_fc */ false) - .SetAvailableSize(size) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(WritingMode::kHorizontalTb, + WritingMode::kHorizontalTb, + /* is_new_fc */ false); + builder.SetAvailableSize(size); + NGConstraintSpace constraint_space = builder.ToConstraintSpace(); NGInlineChildLayoutContext context; scoped_refptr<const NGLayoutResult> layout_result =
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc index 37b7eaa..3ebde3c 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -1055,16 +1055,15 @@ LayoutUnit available_inline_size = mode == NGLineBreakerMode::kMaxContent ? LayoutUnit::Max() : LayoutUnit(); - NGConstraintSpace space = - NGConstraintSpaceBuilder(/* parent_writing_mode */ writing_mode, - /* out_writing_mode */ writing_mode, - /* is_new_fc */ false) - .SetTextDirection(style.Direction()) - .SetAvailableSize({available_inline_size, kIndefiniteSize}) - .SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()}) - .SetReplacedPercentageResolutionSize({LayoutUnit(), LayoutUnit()}) - .SetIsIntermediateLayout(true) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(/* parent_writing_mode */ writing_mode, + /* out_writing_mode */ writing_mode, + /* is_new_fc */ false); + builder.SetTextDirection(style.Direction()); + builder.SetAvailableSize({available_inline_size, kIndefiniteSize}); + builder.SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()}); + builder.SetReplacedPercentageResolutionSize({LayoutUnit(), LayoutUnit()}); + builder.SetIsIntermediateLayout(true); + NGConstraintSpace space = builder.ToConstraintSpace(); NGExclusionSpace empty_exclusion_space; NGPositionedFloatVector empty_leading_floats;
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc index 64bd410..32ee584 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -124,12 +124,11 @@ void CreateLine( NGInlineNode node, Vector<scoped_refptr<const NGPhysicalTextFragment>>* fragments_out) { - NGConstraintSpace constraint_space = - NGConstraintSpaceBuilder(WritingMode::kHorizontalTb, - WritingMode::kHorizontalTb, - /* is_new_fc */ false) - .SetAvailableSize({LayoutUnit::Max(), LayoutUnit(-1)}) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(WritingMode::kHorizontalTb, + WritingMode::kHorizontalTb, + /* is_new_fc */ false); + builder.SetAvailableSize({LayoutUnit::Max(), LayoutUnit(-1)}); + NGConstraintSpace constraint_space = builder.ToConstraintSpace(); NGInlineChildLayoutContext context; scoped_refptr<const NGLayoutResult> result = NGInlineLayoutAlgorithm(node, constraint_space,
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc index df93ec37..1cccec65 100644 --- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc +++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -34,12 +34,11 @@ node.PrepareLayoutIfNeeded(); - NGConstraintSpace space = - NGConstraintSpaceBuilder(WritingMode::kHorizontalTb, - WritingMode::kHorizontalTb, - /* is_new_fc */ false) - .SetAvailableSize({available_width, kIndefiniteSize}) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(WritingMode::kHorizontalTb, + WritingMode::kHorizontalTb, + /* is_new_fc */ false); + builder.SetAvailableSize({available_width, kIndefiniteSize}); + NGConstraintSpace space = builder.ToConstraintSpace(); scoped_refptr<NGInlineBreakToken> break_token;
diff --git a/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc index a618a18..b4b07d4e 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
@@ -105,15 +105,15 @@ ? NGFragmentationType::kFragmentColumn : NGFragmentationType::kFragmentNone; - return NGConstraintSpaceBuilder(writing_mode, writing_mode, - is_new_formatting_context) - .SetAvailableSize(size) - .SetPercentageResolutionSize(size) - .SetTextDirection(direction) - .SetIsShrinkToFit(shrink_to_fit) - .SetFragmentainerSpaceAtBfcStart(fragmentainer_space_available) - .SetFragmentationType(block_fragmentation) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(writing_mode, writing_mode, + is_new_formatting_context); + builder.SetAvailableSize(size); + builder.SetPercentageResolutionSize(size); + builder.SetTextDirection(direction); + builder.SetIsShrinkToFit(shrink_to_fit); + builder.SetFragmentainerSpaceAtBfcStart(fragmentainer_space_available); + builder.SetFragmentationType(block_fragmentation); + return builder.ToConstraintSpace(); } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc index fd5330f..561ea509 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -2152,13 +2152,12 @@ // properties to calculate the line-left offset, we also need to calculate its // inline size first. if (!is_new_fc && needs_inline_size) { - NGConstraintSpace space = - NGConstraintSpaceBuilder(ConstraintSpace(), - child_style.GetWritingMode(), - /* is_new_fc */ false) - .SetAvailableSize(child_available_size_) - .SetPercentageResolutionSize(child_percentage_size_) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(ConstraintSpace(), + child_style.GetWritingMode(), + /* is_new_fc */ false); + builder.SetAvailableSize(child_available_size_); + builder.SetPercentageResolutionSize(child_percentage_size_); + NGConstraintSpace space = builder.ToConstraintSpace(); NGBoxStrut child_border_padding = ComputeBorders(space, child) + ComputePadding(space, child.Style()); @@ -2193,9 +2192,9 @@ child_writing_mode)) builder.SetIsShrinkToFit(child_style.LogicalWidth().IsAuto()); - builder.SetAvailableSize(child_available_size) - .SetPercentageResolutionSize(child_percentage_size_) - .SetReplacedPercentageResolutionSize(replaced_child_percentage_size_); + builder.SetAvailableSize(child_available_size); + builder.SetPercentageResolutionSize(child_percentage_size_); + builder.SetReplacedPercentageResolutionSize(replaced_child_percentage_size_); if (Node().IsTableCell()) { // If we have a fixed block-size we are in the "layout" phase. @@ -2211,8 +2210,8 @@ if (NGBaseline::ShouldPropagateBaselines(child)) builder.AddBaselineRequests(ConstraintSpace().BaselineRequests()); - builder.SetBfcOffset(child_data.bfc_offset_estimate) - .SetMarginStrut(child_data.margin_strut); + builder.SetBfcOffset(child_data.bfc_offset_estimate); + builder.SetMarginStrut(child_data.margin_strut); bool has_bfc_block_offset = container_builder_.BfcBlockOffset().has_value();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc index a693f231..b008db5 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -231,17 +231,17 @@ )HTML"); auto create_space = [&](auto size) -> NGConstraintSpace { - return NGConstraintSpaceBuilder(WritingMode::kHorizontalTb, - WritingMode::kHorizontalTb, - /* is_new_formatting_context */ false) - .SetAvailableSize(size) - .SetPercentageResolutionSize(size) - .SetTextDirection(TextDirection::kLtr) - .AddBaselineRequest({NGBaselineAlgorithmType::kAtomicInline, - FontBaseline::kAlphabeticBaseline}) - .AddBaselineRequest({NGBaselineAlgorithmType::kFirstLine, - FontBaseline::kAlphabeticBaseline}) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(WritingMode::kHorizontalTb, + WritingMode::kHorizontalTb, + /* is_new_formatting_context */ false); + builder.SetAvailableSize(size); + builder.SetPercentageResolutionSize(size); + builder.SetTextDirection(TextDirection::kLtr); + builder.AddBaselineRequest({NGBaselineAlgorithmType::kAtomicInline, + FontBaseline::kAlphabeticBaseline}); + builder.AddBaselineRequest({NGBaselineAlgorithmType::kFirstLine, + FontBaseline::kAlphabeticBaseline}); + return builder.ToConstraintSpace(); }; NGConstraintSpace space100 = @@ -398,18 +398,18 @@ )HTML"); auto create_space = [&](auto size, auto bfc_offset) -> NGConstraintSpace { - return NGConstraintSpaceBuilder(WritingMode::kHorizontalTb, - WritingMode::kHorizontalTb, - /* is_new_formatting_context */ false) - .SetAvailableSize(size) - .SetPercentageResolutionSize(size) - .SetTextDirection(TextDirection::kLtr) - .AddBaselineRequest({NGBaselineAlgorithmType::kAtomicInline, - FontBaseline::kAlphabeticBaseline}) - .AddBaselineRequest({NGBaselineAlgorithmType::kFirstLine, - FontBaseline::kAlphabeticBaseline}) - .SetBfcOffset(bfc_offset) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(WritingMode::kHorizontalTb, + WritingMode::kHorizontalTb, + /* is_new_formatting_context */ false); + builder.SetAvailableSize(size); + builder.SetPercentageResolutionSize(size); + builder.SetTextDirection(TextDirection::kLtr); + builder.AddBaselineRequest({NGBaselineAlgorithmType::kAtomicInline, + FontBaseline::kAlphabeticBaseline}); + builder.AddBaselineRequest({NGBaselineAlgorithmType::kFirstLine, + FontBaseline::kAlphabeticBaseline}); + builder.SetBfcOffset(bfc_offset); + return builder.ToConstraintSpace(); }; NGConstraintSpace space200 =
diff --git a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc index effd5af..586a526d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_block_node.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -167,11 +167,12 @@ NGConstraintSpaceBuilder CreateConstraintSpaceBuilderForMinMax( NGBlockNode node) { - return NGConstraintSpaceBuilder(node.Style().GetWritingMode(), - node.Style().GetWritingMode(), - node.CreatesNewFormattingContext()) - .SetTextDirection(node.Style().Direction()) - .SetIsIntermediateLayout(true); + NGConstraintSpaceBuilder builder(node.Style().GetWritingMode(), + node.Style().GetWritingMode(), + node.CreatesNewFormattingContext()); + builder.SetTextDirection(node.Style().Direction()); + builder.SetIsIntermediateLayout(true); + return builder; } LayoutUnit CalculateAvailableInlineSizeForLegacy( @@ -548,11 +549,11 @@ .InlineSize(); // Now, redo with infinite space for max_content - NGConstraintSpace infinite_constraint_space = - CreateConstraintSpaceBuilderForMinMax(*this) - .SetAvailableSize({LayoutUnit::Max(), LayoutUnit()}) - .SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()}) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder = + CreateConstraintSpaceBuilderForMinMax(*this); + builder.SetAvailableSize({LayoutUnit::Max(), LayoutUnit()}); + builder.SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()}); + NGConstraintSpace infinite_constraint_space = builder.ToConstraintSpace(); layout_result = Layout(infinite_constraint_space); NGBoxFragment max_fragment( @@ -983,15 +984,14 @@ {NGBaselineAlgorithmType::kAtomicInline, baseline_type}); } - NGConstraintSpace constraint_space = - builder.SetIsShrinkToFit(Style().LogicalWidth().IsAuto()) - .SetAvailableSize(parent_constraint_space.AvailableSize()) - .SetPercentageResolutionSize( - parent_constraint_space.PercentageResolutionSize()) - .SetReplacedPercentageResolutionSize( - parent_constraint_space.ReplacedPercentageResolutionSize()) - .SetTextDirection(Style().Direction()) - .ToConstraintSpace(); + builder.SetIsShrinkToFit(Style().LogicalWidth().IsAuto()); + builder.SetAvailableSize(parent_constraint_space.AvailableSize()); + builder.SetPercentageResolutionSize( + parent_constraint_space.PercentageResolutionSize()); + builder.SetReplacedPercentageResolutionSize( + parent_constraint_space.ReplacedPercentageResolutionSize()); + builder.SetTextDirection(Style().Direction()); + NGConstraintSpace constraint_space = builder.ToConstraintSpace(); scoped_refptr<const NGLayoutResult> result = Layout(constraint_space); // TODO(kojii): Investigate why ClearNeedsLayout() isn't called automatically // when it's being laid out.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc index 736d92a..481bca1 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -85,8 +85,7 @@ children_.resize(0); } -NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddBreakBeforeChild( - NGLayoutInputNode child) { +void NGBoxFragmentBuilder::AddBreakBeforeChild(NGLayoutInputNode child) { DCHECK(has_block_fragmentation_); if (auto* child_inline_node = DynamicTo<NGInlineNode>(child)) { if (inline_break_tokens_.IsEmpty()) { @@ -99,15 +98,13 @@ *child_inline_node, /* style */ nullptr, /* item_index */ 0, /* text_offset */ 0, NGInlineBreakToken::kDefault)); } - return *this; + return; } auto token = NGBlockBreakToken::CreateBreakBefore(child); child_break_tokens_.push_back(token); - return *this; } -NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddBreakBeforeLine( - int line_number) { +void NGBoxFragmentBuilder::AddBreakBeforeLine(int line_number) { DCHECK(has_block_fragmentation_); DCHECK_GT(line_number, 0); DCHECK_LE(unsigned(line_number), inline_break_tokens_.size()); @@ -136,18 +133,15 @@ // broken floats, which are resumed and positioned by the parent block layout // algorithm, need to be ignored by the inline layout algorithm. To<NGInlineBreakToken>(inline_break_tokens_.back().get())->SetIgnoreFloats(); - return *this; } -NGBoxFragmentBuilder& NGBoxFragmentBuilder::AddResult( - const NGLayoutResult& child_layout_result, - const LogicalOffset offset, - const LayoutInline* inline_container) { +void NGBoxFragmentBuilder::AddResult(const NGLayoutResult& child_layout_result, + const LogicalOffset offset, + const LayoutInline* inline_container) { const auto& fragment = child_layout_result.PhysicalFragment(); AddChild(fragment, offset, inline_container); if (fragment.IsBox()) PropagateBreak(child_layout_result); - return *this; } void NGBoxFragmentBuilder::AddOutOfFlowLegacyCandidate(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h index 1cac2e4..11c0e028 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -56,17 +56,15 @@ layout_object_ = layout_object; } - NGBoxFragmentBuilder& SetInitialFragmentGeometry( + void SetInitialFragmentGeometry( const NGFragmentGeometry& initial_fragment_geometry) { initial_fragment_geometry_ = &initial_fragment_geometry; size_ = initial_fragment_geometry_->border_box_size; is_initial_block_size_indefinite_ = size_.block_size == kIndefiniteSize; - return *this; } - NGBoxFragmentBuilder& SetIntrinsicBlockSize(LayoutUnit intrinsic_block_size) { + void SetIntrinsicBlockSize(LayoutUnit intrinsic_block_size) { intrinsic_block_size_ = intrinsic_block_size; - return *this; } const NGBoxStrut& Borders() const { DCHECK(initial_fragment_geometry_); @@ -91,17 +89,17 @@ // Add a break token for a child that doesn't yet have any fragments, because // its first fragment is to be produced in the next fragmentainer. This will // add a break token for the child, but no fragment. - NGBoxFragmentBuilder& AddBreakBeforeChild(NGLayoutInputNode child); + void AddBreakBeforeChild(NGLayoutInputNode child); // Prepare for a break token before the specified line. - NGBoxFragmentBuilder& AddBreakBeforeLine(int line_number); + void AddBreakBeforeLine(int line_number); // Add a layout result. This involves appending the fragment and its relative // offset to the builder, but also keeping track of out-of-flow positioned // descendants, propagating fragmentainer breaks, and more. - NGBoxFragmentBuilder& AddResult(const NGLayoutResult&, - const LogicalOffset, - const LayoutInline* = nullptr); + void AddResult(const NGLayoutResult&, + const LogicalOffset, + const LayoutInline* = nullptr); void AddOutOfFlowLegacyCandidate(NGBlockNode, const NGLogicalStaticPosition&, @@ -110,33 +108,25 @@ // Set how much of the block-size we've used so far for this box. This will be // the sum of the block-size of all previous fragments PLUS the one we're // building now. - NGBoxFragmentBuilder& SetConsumedBlockSize(LayoutUnit size) { - consumed_block_size_ = size; - return *this; - } + void SetConsumedBlockSize(LayoutUnit size) { consumed_block_size_ = size; } // Specify that we broke. // // This will result in a fragment which has an unfinished break token. - NGBoxFragmentBuilder& SetDidBreak() { - did_break_ = true; - return *this; - } + void SetDidBreak() { did_break_ = true; } - NGBoxFragmentBuilder& SetHasForcedBreak() { + void SetHasForcedBreak() { has_forced_break_ = true; minimal_space_shortage_ = LayoutUnit(); - return *this; } // Report space shortage, i.e. how much more space would have been sufficient // to prevent some piece of content from breaking. This information may be // used by the column balancer to stretch columns. - NGBoxFragmentBuilder& PropagateSpaceShortage(LayoutUnit space_shortage) { + void PropagateSpaceShortage(LayoutUnit space_shortage) { DCHECK_GT(space_shortage, LayoutUnit()); if (minimal_space_shortage_ > space_shortage) minimal_space_shortage_ = space_shortage; - return *this; } void SetInitialBreakBefore(EBreakBetween break_before) { @@ -184,31 +174,20 @@ NGLayoutResult::NGLayoutResultStatus); NGPhysicalFragment::NGBoxType BoxType() const; - NGBoxFragmentBuilder& SetBoxType(NGPhysicalFragment::NGBoxType box_type) { + void SetBoxType(NGPhysicalFragment::NGBoxType box_type) { box_type_ = box_type; - return *this; } - NGBoxFragmentBuilder& SetIsFieldsetContainer() { - is_fieldset_container_ = true; - return *this; - } - NGBoxFragmentBuilder& SetIsLegacyLayoutRoot() { - is_legacy_layout_root_ = true; - return *this; - } + void SetIsFieldsetContainer() { is_fieldset_container_ = true; } + void SetIsLegacyLayoutRoot() { is_legacy_layout_root_ = true; } bool DidBreak() const { return did_break_; } - NGBoxFragmentBuilder& SetBorderEdges(NGBorderEdges border_edges) { + void SetBorderEdges(NGBorderEdges border_edges) { border_edges_ = border_edges; - return *this; } // Either this function or SetBoxType must be called before ToBoxFragment(). - NGBoxFragmentBuilder& SetIsNewFormattingContext(bool is_new_fc) { - is_new_fc_ = is_new_fc; - return *this; - } + void SetIsNewFormattingContext(bool is_new_fc) { is_new_fc_ = is_new_fc; } // Layout algorithms should call this function for each baseline request in // the constraint space.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc index c62be00d..ee5a6d3 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -88,16 +88,16 @@ {NGBaselineAlgorithmType::kFirstLine, baseline_type}); } - return builder.SetAvailableSize(available_size) - .SetPercentageResolutionSize(percentage_size) - .SetIsFixedInlineSize(fixed_inline) - .SetIsFixedBlockSize(fixed_block) - .SetIsFixedBlockSizeIndefinite(!fixed_block_is_definite) - .SetIsShrinkToFit( - style.LogicalWidth().IsAuto() && - block.SizesLogicalWidthToFitContent(style.LogicalWidth())) - .SetTextDirection(style.Direction()) - .ToConstraintSpace(); + builder.SetAvailableSize(available_size); + builder.SetPercentageResolutionSize(percentage_size); + builder.SetIsFixedInlineSize(fixed_inline); + builder.SetIsFixedBlockSize(fixed_block); + builder.SetIsFixedBlockSizeIndefinite(!fixed_block_is_definite); + builder.SetIsShrinkToFit( + style.LogicalWidth().IsAuto() && + block.SizesLogicalWidthToFitContent(style.LogicalWidth())); + builder.SetTextDirection(style.Direction()); + return builder.ToConstraintSpace(); } String NGConstraintSpace::ToString() const {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc index ad673637..9d8f6e5c 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
@@ -26,7 +26,7 @@ } // namespace -NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetPercentageResolutionSize( +void NGConstraintSpaceBuilder::SetPercentageResolutionSize( LogicalSize percentage_resolution_size) { #if DCHECK_IS_ON() DCHECK(is_available_size_set_); @@ -68,12 +68,9 @@ percentage_resolution_size.inline_size; } } - - return *this; } -NGConstraintSpaceBuilder& -NGConstraintSpaceBuilder::SetReplacedPercentageResolutionSize( +void NGConstraintSpaceBuilder::SetReplacedPercentageResolutionSize( LogicalSize replaced_percentage_resolution_size) { #if DCHECK_IS_ON() DCHECK(is_available_size_set_); @@ -111,8 +108,6 @@ block_size; } } - - return *this; } } // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h index fffe7f1d..bdc90b3 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -67,7 +67,7 @@ *inline_size = orthogonal_fallback_inline_size_; } - NGConstraintSpaceBuilder& SetAvailableSize(LogicalSize available_size) { + void SetAvailableSize(LogicalSize available_size) { #if DCHECK_IS_ON() is_available_size_set_ = true; #endif @@ -77,16 +77,13 @@ space_.available_size_.Transpose(); AdjustInlineSizeIfNeeded(&space_.available_size_.inline_size); } - - return *this; } // Set percentage resolution size. Prior to calling this method, // SetAvailableSize() must have been called, since we'll compare the input // against the available size set, because if they are equal in either // dimension, we won't have to store the values separately. - NGConstraintSpaceBuilder& SetPercentageResolutionSize( - LogicalSize percentage_resolution_size); + void SetPercentageResolutionSize(LogicalSize percentage_resolution_size); // Set percentage resolution size for replaced content (a special quirk inside // tables). Only honored if the writing modes (container vs. child) are @@ -97,78 +94,63 @@ // dimension, we won't have to store the values separately. Additionally, // SetPercentageResolutionSize() must have been called, since we'll override // with that value on orthogonal writing mode roots. - NGConstraintSpaceBuilder& SetReplacedPercentageResolutionSize( + void SetReplacedPercentageResolutionSize( LogicalSize replaced_percentage_resolution_size); // Set the fallback available inline-size for an orthogonal child. The size is // the inline size in the writing mode of the orthogonal child. - NGConstraintSpaceBuilder& SetOrthogonalFallbackInlineSize(LayoutUnit size) { + void SetOrthogonalFallbackInlineSize(LayoutUnit size) { orthogonal_fallback_inline_size_ = size; - return *this; } - NGConstraintSpaceBuilder& SetFragmentainerBlockSize(LayoutUnit size) { + void SetFragmentainerBlockSize(LayoutUnit size) { #if DCHECK_IS_ON() DCHECK(!is_fragmentainer_block_size_set_); is_fragmentainer_block_size_set_ = true; #endif if (size != kIndefiniteSize) space_.EnsureRareData()->fragmentainer_block_size = size; - return *this; } - NGConstraintSpaceBuilder& SetFragmentainerSpaceAtBfcStart(LayoutUnit space) { + void SetFragmentainerSpaceAtBfcStart(LayoutUnit space) { #if DCHECK_IS_ON() DCHECK(!is_fragmentainer_space_at_bfc_start_set_); is_fragmentainer_space_at_bfc_start_set_ = true; #endif if (space != kIndefiniteSize) space_.EnsureRareData()->fragmentainer_space_at_bfc_start = space; - return *this; } - NGConstraintSpaceBuilder& SetTextDirection(TextDirection direction) { + void SetTextDirection(TextDirection direction) { space_.bitfields_.direction = static_cast<unsigned>(direction); - return *this; } - NGConstraintSpaceBuilder& SetIsFixedInlineSize(bool b) { + void SetIsFixedInlineSize(bool b) { if (LIKELY(is_in_parallel_flow_)) space_.bitfields_.is_fixed_inline_size = b; else space_.bitfields_.is_fixed_block_size = b; - - return *this; } - NGConstraintSpaceBuilder& SetIsFixedBlockSize(bool b) { + void SetIsFixedBlockSize(bool b) { if (LIKELY(is_in_parallel_flow_)) space_.bitfields_.is_fixed_block_size = b; else space_.bitfields_.is_fixed_inline_size = b; - - return *this; } - NGConstraintSpaceBuilder& SetIsFixedBlockSizeIndefinite(bool b) { + void SetIsFixedBlockSizeIndefinite(bool b) { if (LIKELY(is_in_parallel_flow_ || !force_orthogonal_writing_mode_root_)) space_.bitfields_.is_fixed_block_size_indefinite = b; - - return *this; } - NGConstraintSpaceBuilder& SetIsShrinkToFit(bool b) { - space_.bitfields_.is_shrink_to_fit = b; - return *this; - } + void SetIsShrinkToFit(bool b) { space_.bitfields_.is_shrink_to_fit = b; } - NGConstraintSpaceBuilder& SetIsIntermediateLayout(bool b) { + void SetIsIntermediateLayout(bool b) { space_.bitfields_.is_intermediate_layout = b; - return *this; } - NGConstraintSpaceBuilder& SetFragmentationType( - NGFragmentationType fragmentation_type) { + void SetFragmentationType(NGFragmentationType fragmentation_type) { #if DCHECK_IS_ON() DCHECK(!is_block_direction_fragmentation_type_set_); is_block_direction_fragmentation_type_set_ = true; @@ -177,63 +159,48 @@ space_.EnsureRareData()->block_direction_fragmentation_type = fragmentation_type; } - return *this; } - NGConstraintSpaceBuilder& SetSeparateLeadingFragmentainerMargins(bool b) { + void SetSeparateLeadingFragmentainerMargins(bool b) { space_.bitfields_.has_separate_leading_fragmentainer_margins = b; - return *this; } - NGConstraintSpaceBuilder& SetIsAnonymous(bool b) { - space_.bitfields_.is_anonymous = b; - return *this; - } + void SetIsAnonymous(bool b) { space_.bitfields_.is_anonymous = b; } - NGConstraintSpaceBuilder& SetUseFirstLineStyle(bool b) { + void SetUseFirstLineStyle(bool b) { space_.bitfields_.use_first_line_style = b; - return *this; } - NGConstraintSpaceBuilder& SetAncestorHasClearancePastAdjoiningFloats() { + void SetAncestorHasClearancePastAdjoiningFloats() { space_.bitfields_.ancestor_has_clearance_past_adjoining_floats = true; - return *this; } - NGConstraintSpaceBuilder& SetAdjoiningObjectTypes( - NGAdjoiningObjectTypes adjoining_object_types) { + void SetAdjoiningObjectTypes(NGAdjoiningObjectTypes adjoining_object_types) { if (!is_new_fc_) { space_.bitfields_.adjoining_object_types = static_cast<unsigned>(adjoining_object_types); } - - return *this; } - NGConstraintSpaceBuilder& SetMarginStrut(const NGMarginStrut& margin_strut) { + void SetMarginStrut(const NGMarginStrut& margin_strut) { #if DCHECK_IS_ON() DCHECK(!is_margin_strut_set_); is_margin_strut_set_ = true; #endif if (!is_new_fc_ && margin_strut != NGMarginStrut()) space_.EnsureRareData()->margin_strut = margin_strut; - - return *this; } - NGConstraintSpaceBuilder& SetBfcOffset(const NGBfcOffset& bfc_offset) { + void SetBfcOffset(const NGBfcOffset& bfc_offset) { if (!is_new_fc_) { if (space_.HasRareData()) space_.rare_data_->bfc_offset = bfc_offset; else space_.bfc_offset_ = bfc_offset; } - - return *this; } - NGConstraintSpaceBuilder& SetOptimisticBfcBlockOffset( - LayoutUnit optimistic_bfc_block_offset) { + void SetOptimisticBfcBlockOffset(LayoutUnit optimistic_bfc_block_offset) { #if DCHECK_IS_ON() DCHECK(!is_optimistic_bfc_block_offset_set_); is_optimistic_bfc_block_offset_set_ = true; @@ -242,12 +209,9 @@ space_.EnsureRareData()->optimistic_bfc_block_offset = optimistic_bfc_block_offset; } - - return *this; } - NGConstraintSpaceBuilder& SetForcedBfcBlockOffset( - LayoutUnit forced_bfc_block_offset) { + void SetForcedBfcBlockOffset(LayoutUnit forced_bfc_block_offset) { #if DCHECK_IS_ON() DCHECK(!is_forced_bfc_block_offset_set_); is_forced_bfc_block_offset_set_ = true; @@ -256,49 +220,38 @@ space_.EnsureRareData()->forced_bfc_block_offset = forced_bfc_block_offset; } - - return *this; } - NGConstraintSpaceBuilder& SetClearanceOffset(LayoutUnit clearance_offset) { + void SetClearanceOffset(LayoutUnit clearance_offset) { #if DCHECK_IS_ON() DCHECK(!is_clearance_offset_set_); is_clearance_offset_set_ = true; #endif if (!is_new_fc_ && clearance_offset != LayoutUnit::Min()) space_.EnsureRareData()->clearance_offset = clearance_offset; - - return *this; } - NGConstraintSpaceBuilder& SetTableCellChildLayoutPhase( + void SetTableCellChildLayoutPhase( NGTableCellChildLayoutPhase table_cell_child_layout_phase) { space_.bitfields_.table_cell_child_layout_phase = static_cast<unsigned>(table_cell_child_layout_phase); - return *this; } - NGConstraintSpaceBuilder& SetIsInRestrictedBlockSizeTableCell() { + void SetIsInRestrictedBlockSizeTableCell() { space_.bitfields_.is_in_restricted_block_size_table_cell = true; - return *this; } - NGConstraintSpaceBuilder& SetExclusionSpace( - const NGExclusionSpace& exclusion_space) { + void SetExclusionSpace(const NGExclusionSpace& exclusion_space) { if (!is_new_fc_) space_.exclusion_space_ = exclusion_space; - - return *this; } void AddBaselineRequests(const NGBaselineRequestList requests) { DCHECK(baseline_requests_.IsEmpty()); baseline_requests_.AppendVector(requests); } - NGConstraintSpaceBuilder& AddBaselineRequest( - const NGBaselineRequest request) { + void AddBaselineRequest(const NGBaselineRequest request) { baseline_requests_.push_back(request); - return *this; } // Creates a new constraint space.
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc index d738e141..4ec7848 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -24,7 +24,7 @@ } // namespace -NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddChild( +void NGContainerFragmentBuilder::AddChild( const NGPhysicalContainerFragment& child, const LogicalOffset& child_offset, const LayoutInline* inline_container) { @@ -129,7 +129,6 @@ } AddChildInternal(&child, child_offset); - return *this; } void NGContainerFragmentBuilder::AddChildInternal( @@ -172,8 +171,7 @@ return LogicalOffset(); } -NGContainerFragmentBuilder& -NGContainerFragmentBuilder::AddOutOfFlowChildCandidate( +void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate( NGBlockNode child, const LogicalOffset& child_offset, base::Optional<TextDirection> container_direction) { @@ -194,14 +192,11 @@ IsLtr(direction) ? NGLogicalStaticPosition::InlineEdge::kInlineStart : NGLogicalStaticPosition::InlineEdge::kInlineEnd, NGLogicalStaticPosition::BlockEdge::kBlockStart}); - - return *this; } -NGContainerFragmentBuilder& NGContainerFragmentBuilder::AddOutOfFlowDescendant( +void NGContainerFragmentBuilder::AddOutOfFlowDescendant( const NGLogicalOutOfFlowPositionedNode& descendant) { oof_positioned_descendants_.push_back(descendant); - return *this; } void NGContainerFragmentBuilder::SwapOutOfFlowPositionedCandidates(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h index b7b1d38..0827130d 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -45,9 +45,8 @@ typedef Vector<ChildWithOffset, 4> ChildrenVector; LayoutUnit BfcLineOffset() const { return bfc_line_offset_; } - NGContainerFragmentBuilder& SetBfcLineOffset(LayoutUnit bfc_line_offset) { + void SetBfcLineOffset(LayoutUnit bfc_line_offset) { bfc_line_offset_ = bfc_line_offset; - return *this; } // The BFC block-offset is where this fragment was positioned within the BFC. @@ -55,47 +54,34 @@ const base::Optional<LayoutUnit>& BfcBlockOffset() const { return bfc_block_offset_; } - NGContainerFragmentBuilder& SetBfcBlockOffset(LayoutUnit bfc_block_offset) { + void SetBfcBlockOffset(LayoutUnit bfc_block_offset) { bfc_block_offset_ = bfc_block_offset; - return *this; } - NGContainerFragmentBuilder& ResetBfcBlockOffset() { - bfc_block_offset_.reset(); - return *this; - } + void ResetBfcBlockOffset() { bfc_block_offset_.reset(); } - NGContainerFragmentBuilder& SetEndMarginStrut( - const NGMarginStrut& end_margin_strut) { + void SetEndMarginStrut(const NGMarginStrut& end_margin_strut) { end_margin_strut_ = end_margin_strut; - return *this; } - NGContainerFragmentBuilder& SetExclusionSpace( - NGExclusionSpace&& exclusion_space) { + void SetExclusionSpace(NGExclusionSpace&& exclusion_space) { exclusion_space_ = std::move(exclusion_space); - return *this; } const NGUnpositionedListMarker& UnpositionedListMarker() const { return unpositioned_list_marker_; } - NGContainerFragmentBuilder& SetUnpositionedListMarker( - const NGUnpositionedListMarker& marker) { + void SetUnpositionedListMarker(const NGUnpositionedListMarker& marker) { DCHECK(!unpositioned_list_marker_ || !marker); unpositioned_list_marker_ = marker; - return *this; } - NGContainerFragmentBuilder& AddChild( - const NGPhysicalContainerFragment&, - const LogicalOffset&, - const LayoutInline* inline_container = nullptr); + void AddChild(const NGPhysicalContainerFragment&, + const LogicalOffset&, + const LayoutInline* inline_container = nullptr); - NGContainerFragmentBuilder& AddChild( - scoped_refptr<const NGPhysicalTextFragment> child, - const LogicalOffset& offset) { + void AddChild(scoped_refptr<const NGPhysicalTextFragment> child, + const LogicalOffset& offset) { AddChildInternal(child, offset); - return *this; } const ChildrenVector& Children() const { return children_; } @@ -129,12 +115,12 @@ // // @param direction: default candidate direction is builder's direction. // Pass in direction if candidates direction does not match. - NGContainerFragmentBuilder& AddOutOfFlowChildCandidate( + void AddOutOfFlowChildCandidate( NGBlockNode, const LogicalOffset& child_offset, base::Optional<TextDirection> container_direction = base::nullopt); - NGContainerFragmentBuilder& AddOutOfFlowDescendant( + void AddOutOfFlowDescendant( const NGLogicalOutOfFlowPositionedNode& descendant); void SwapOutOfFlowPositionedCandidates( @@ -156,39 +142,23 @@ SwapOutOfFlowPositionedCandidates(&oof_positioned_descendants_, nullptr); } - NGContainerFragmentBuilder& SetIsSelfCollapsing() { - is_self_collapsing_ = true; - return *this; - } + void SetIsSelfCollapsing() { is_self_collapsing_ = true; } - NGContainerFragmentBuilder& SetIsPushedByFloats() { - is_pushed_by_floats_ = true; - return *this; - } + void SetIsPushedByFloats() { is_pushed_by_floats_ = true; } bool IsPushedByFloats() const { return is_pushed_by_floats_; } - NGContainerFragmentBuilder& ResetAdjoiningObjectTypes() { - adjoining_object_types_ = kAdjoiningNone; - return *this; - } - NGContainerFragmentBuilder& AddAdjoiningObjectTypes( - NGAdjoiningObjectTypes adjoining_object_types) { + void ResetAdjoiningObjectTypes() { adjoining_object_types_ = kAdjoiningNone; } + void AddAdjoiningObjectTypes(NGAdjoiningObjectTypes adjoining_object_types) { adjoining_object_types_ |= adjoining_object_types; - return *this; } - NGContainerFragmentBuilder& SetAdjoiningObjectTypes( - NGAdjoiningObjectTypes adjoining_object_types) { + void SetAdjoiningObjectTypes(NGAdjoiningObjectTypes adjoining_object_types) { adjoining_object_types_ = adjoining_object_types; - return *this; } NGAdjoiningObjectTypes AdjoiningObjectTypes() const { return adjoining_object_types_; } - NGContainerFragmentBuilder& SetHasBlockFragmentation() { - has_block_fragmentation_ = true; - return *this; - } + void SetHasBlockFragmentation() { has_block_fragmentation_ = true; } const NGConstraintSpace* ConstraintSpace() const { return space_; }
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 78d93ed..3c5d9f6 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
@@ -162,10 +162,9 @@ // TODO(dgrogan): Change SetPercentageResolutionSize everywhere in this file // to use CalculateChildPercentageSize. - NGConstraintSpace child_space = - space_builder.SetAvailableSize(content_box_size_) - .SetPercentageResolutionSize(content_box_size_) - .ToConstraintSpace(); + space_builder.SetAvailableSize(content_box_size_); + space_builder.SetPercentageResolutionSize(content_box_size_); + NGConstraintSpace child_space = space_builder.ToConstraintSpace(); NGBoxStrut border_padding_in_child_writing_mode = ComputeBorders(child_space, child) +
diff --git a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc index 7a58bdb..ef8c1cc 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -83,12 +83,12 @@ builder.SetFragmentationType(NGFragmentationType::kFragmentNone); } - return builder.SetAvailableSize(float_available_size) - .SetPercentageResolutionSize(float_percentage_size) - .SetReplacedPercentageResolutionSize(float_replaced_percentage_size) - .SetIsShrinkToFit(style.LogicalWidth().IsAuto()) - .SetTextDirection(style.Direction()) - .ToConstraintSpace(); + builder.SetAvailableSize(float_available_size); + builder.SetPercentageResolutionSize(float_percentage_size); + builder.SetReplacedPercentageResolutionSize(float_replaced_percentage_size); + builder.SetIsShrinkToFit(style.LogicalWidth().IsAuto()); + builder.SetTextDirection(style.Direction()); + return builder.ToConstraintSpace(); } std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
diff --git a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h index 03aa4a4..a1ceb920 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h +++ b/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -27,16 +27,14 @@ DCHECK(style_); return *style_; } - NGFragmentBuilder& SetStyleVariant(NGStyleVariant style_variant) { + void SetStyleVariant(NGStyleVariant style_variant) { style_variant_ = style_variant; - return *this; } - NGFragmentBuilder& SetStyle(scoped_refptr<const ComputedStyle> style, - NGStyleVariant style_variant) { + void SetStyle(scoped_refptr<const ComputedStyle> style, + NGStyleVariant style_variant) { DCHECK(style); style_ = std::move(style); style_variant_ = style_variant; - return *this; } WritingMode GetWritingMode() const { return writing_mode_; }
diff --git a/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc b/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc index b04978e..79f8097 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc
@@ -21,13 +21,14 @@ class NGInlineLayoutTest : public SimTest { public: NGConstraintSpace ConstraintSpaceForElement(LayoutBlockFlow* block_flow) { - return NGConstraintSpaceBuilder(block_flow->Style()->GetWritingMode(), - block_flow->Style()->GetWritingMode(), - /* is_new_fc */ false) - .SetAvailableSize(LogicalSize(LayoutUnit(), LayoutUnit())) - .SetPercentageResolutionSize(LogicalSize(LayoutUnit(), LayoutUnit())) - .SetTextDirection(block_flow->Style()->Direction()) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(block_flow->Style()->GetWritingMode(), + block_flow->Style()->GetWritingMode(), + /* is_new_fc */ false); + builder.SetAvailableSize(LogicalSize(LayoutUnit(), LayoutUnit())); + builder.SetPercentageResolutionSize( + LogicalSize(LayoutUnit(), LayoutUnit())); + builder.SetTextDirection(block_flow->Style()->Direction()); + return builder.ToConstraintSpace(); } };
diff --git a/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc b/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc index 8683d5b..ae32444 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
@@ -26,13 +26,13 @@ WritingMode writing_mode = WritingMode::kHorizontalTb) { LogicalSize size = {LayoutUnit(inline_size), LayoutUnit(block_size)}; - return NGConstraintSpaceBuilder(writing_mode, writing_mode, - /* is_new_fc */ false) - .SetAvailableSize(size) - .SetPercentageResolutionSize(size) - .SetIsFixedInlineSize(fixed_inline) - .SetIsFixedBlockSize(fixed_block) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(writing_mode, writing_mode, + /* is_new_fc */ false); + builder.SetAvailableSize(size); + builder.SetPercentageResolutionSize(size); + builder.SetIsFixedInlineSize(fixed_inline); + builder.SetIsFixedBlockSize(fixed_block); + return builder.ToConstraintSpace(); } class NGLengthUtilsTest : public testing::Test {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc index 971d139..1e46d691 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -482,13 +482,12 @@ container_physical_content_size); // Need a constraint space to resolve offsets. - NGConstraintSpace candidate_constraint_space = - NGConstraintSpaceBuilder(writing_mode_, candidate_writing_mode, - /* is_new_fc */ true) - .SetTextDirection(candidate_direction) - .SetAvailableSize(container_content_size) - .SetPercentageResolutionSize(container_content_size) - .ToConstraintSpace(); + NGConstraintSpaceBuilder builder(writing_mode_, candidate_writing_mode, + /* is_new_fc */ true); + builder.SetTextDirection(candidate_direction); + builder.SetAvailableSize(container_content_size); + builder.SetPercentageResolutionSize(container_content_size); + NGConstraintSpace candidate_constraint_space = builder.ToConstraintSpace(); base::Optional<PaintLayerScrollableArea::FreezeScrollbarsScope> freeze_scrollbars; @@ -753,11 +752,11 @@ // TODO(atotic) will need to be adjusted for scrollbars. NGConstraintSpaceBuilder builder(writing_mode, writing_mode, /* is_new_fc */ true); - builder.SetAvailableSize(available_size) - .SetTextDirection(node.Style().Direction()) - .SetPercentageResolutionSize( - container_content_size_in_candidate_writing_mode) - .SetIsFixedInlineSize(true); + builder.SetAvailableSize(available_size); + builder.SetTextDirection(node.Style().Direction()); + builder.SetPercentageResolutionSize( + container_content_size_in_candidate_writing_mode); + builder.SetIsFixedInlineSize(true); if (block_estimate) builder.SetIsFixedBlockSize(true); NGConstraintSpace space = builder.ToConstraintSpace();
diff --git a/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc index ba44dfd..8af9ebb 100644 --- a/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc +++ b/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
@@ -35,11 +35,11 @@ child.CreatesNewFormattingContext()); SetOrthogonalFallbackInlineSizeIfNeeded(container_style, child, &builder); - return builder.SetAvailableSize(indefinite_size) - .SetPercentageResolutionSize(indefinite_size) - .SetReplacedPercentageResolutionSize(indefinite_size) - .SetIsIntermediateLayout(true) - .ToConstraintSpace(); + builder.SetAvailableSize(indefinite_size); + builder.SetPercentageResolutionSize(indefinite_size); + builder.SetReplacedPercentageResolutionSize(indefinite_size); + builder.SetIsIntermediateLayout(true); + return builder.ToConstraintSpace(); } void SetOrthogonalFallbackInlineSizeIfNeeded(
diff --git a/third_party/blink/renderer/core/layout/scrollbars_test.cc b/third_party/blink/renderer/core/layout/scrollbars_test.cc index afae9ee0..dacbc3ca 100644 --- a/third_party/blink/renderer/core/layout/scrollbars_test.cc +++ b/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -1450,6 +1450,8 @@ class StubWebThemeEngine : public WebThemeEngine { public: + StubWebThemeEngine() { painted_color_scheme_.fill(WebColorScheme::kLight); } + WebSize GetSize(Part part) override { switch (part) { case kPartScrollbarHorizontalThumb: @@ -1469,6 +1471,24 @@ } static constexpr int kMinimumHorizontalLength = 51; static constexpr int kMinimumVerticalLength = 52; + + void Paint(cc::PaintCanvas*, + Part part, + State, + const WebRect&, + const ExtraParams*, + blink::WebColorScheme color_scheme) override { + // Make sure we don't overflow the array. + DCHECK(part <= kPartProgressBar); + painted_color_scheme_[part] = color_scheme; + } + + WebColorScheme GetPaintedPartColorScheme(Part part) const { + return painted_color_scheme_[part]; + } + + private: + std::array<WebColorScheme, kPartProgressBar + 1> painted_color_scheme_; }; constexpr int StubWebThemeEngine::kMinimumHorizontalLength; @@ -2647,6 +2667,63 @@ EXPECT_EQ(51, vertical_track_->MarginBottom()); } +class ScrollbarColorSchemeTest : public ScrollbarAppearanceTest {}; + +INSTANTIATE_TEST_SUITE_P(NonOverlay, + ScrollbarColorSchemeTest, + testing::Values(false)); + +#if defined(OS_ANDROID) || defined(OS_MACOSX) +// Not able to paint non-overlay scrollbars through ThemeEngine on Android or +// Mac. +#define MAYBE_ThemeEnginePaint DISABLED_ThemeEnginePaint +#else +#define MAYBE_ThemeEnginePaint ThemeEnginePaint +#endif + +TEST_P(ScrollbarColorSchemeTest, MAYBE_ThemeEnginePaint) { + ScopedTestingPlatformSupport<ScrollbarTestingPlatformSupport> platform; + ScopedCSSColorSchemeForTest css_feature_scope(true); + + WebView().MainFrameWidget()->Resize(WebSize(800, 600)); + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + #scrollable { + width: 100px; + height: 100px; + overflow: scroll; + color-scheme: dark; + } + #filler { + width: 200px; + height: 200px; + } + </style> + <div id="scrollable"> + <div id="filler"></div> + </div> + )HTML"); + + GetDocument().GetSettings()->SetPreferredColorScheme( + PreferredColorScheme::kDark); + + Compositor().BeginFrame(); + + auto* theme_engine = + static_cast<StubWebThemeEngine*>(Platform::Current()->ThemeEngine()); + EXPECT_EQ(WebColorScheme::kDark, + theme_engine->GetPaintedPartColorScheme( + WebThemeEngine::kPartScrollbarHorizontalThumb)); + EXPECT_EQ(WebColorScheme::kDark, + theme_engine->GetPaintedPartColorScheme( + WebThemeEngine::kPartScrollbarVerticalThumb)); + EXPECT_EQ(WebColorScheme::kDark, theme_engine->GetPaintedPartColorScheme( + WebThemeEngine::kPartScrollbarCorner)); +} + } // namespace } // namespace blink
diff --git a/third_party/blink/renderer/core/loader/cookie_jar.cc b/third_party/blink/renderer/core/loader/cookie_jar.cc index 2445b749..5bb98eac 100644 --- a/third_party/blink/renderer/core/loader/cookie_jar.cc +++ b/third_party/blink/renderer/core/loader/cookie_jar.cc
@@ -22,7 +22,8 @@ RequestRestrictedCookieManagerIfNeeded(); SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Blink.CookieJar.SyncCookiesSetTime"); - backend_->SetCookieFromString(cookie_url, document_->SiteForCookies(), value); + backend_->SetCookieFromString(cookie_url, document_->SiteForCookies(), + document_->TopFrameOrigin(), value); } String CookieJar::Cookies() { @@ -33,7 +34,8 @@ SCOPED_BLINK_UMA_HISTOGRAM_TIMER("Blink.CookieJar.SyncCookiesTime"); RequestRestrictedCookieManagerIfNeeded(); String value; - backend_->GetCookiesString(cookie_url, document_->SiteForCookies(), &value); + backend_->GetCookiesString(cookie_url, document_->SiteForCookies(), + document_->TopFrameOrigin(), &value); return value; } @@ -45,7 +47,7 @@ RequestRestrictedCookieManagerIfNeeded(); bool cookies_enabled = false; backend_->CookiesEnabledFor(cookie_url, document_->SiteForCookies(), - &cookies_enabled); + document_->TopFrameOrigin(), &cookies_enabled); return cookies_enabled; }
diff --git a/third_party/blink/renderer/core/paint/paint_layer.cc b/third_party/blink/renderer/core/paint/paint_layer.cc index 7df0ad07..aa17abe 100644 --- a/third_party/blink/renderer/core/paint/paint_layer.cc +++ b/third_party/blink/renderer/core/paint/paint_layer.cc
@@ -2014,9 +2014,16 @@ z_offset); } - if (layout_object.HasClipPath() && - HitTestClippedOutByClipPath(root_layer, recursion_data.location)) + // Don't hit test the clip-path area when checking for occlusion. This is + // necessary because SVG doesn't support rect-based hit testing, so + // HitTestClippedOutByClipPath may erroneously return true for a rect-based + // hit test). + bool is_occlusion_test = result.GetHitTestRequest().GetType() & + HitTestRequest::kHitTestVisualOverflow; + if (!is_occlusion_test && layout_object.HasClipPath() && + HitTestClippedOutByClipPath(root_layer, recursion_data.location)) { return nullptr; + } // The natural thing would be to keep HitTestingTransformState on the stack, // but it's big, so we heap-allocate.
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc index 59025b0..2ade5fd 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.cc
@@ -1115,6 +1115,10 @@ return GetLayoutBox()->StyleRef().GetScrollBehavior(); } +WebColorScheme PaintLayerScrollableArea::UsedColorScheme() const { + return GetLayoutBox()->StyleRef().UsedColorScheme(); +} + bool PaintLayerScrollableArea::HasHorizontalOverflow() const { // TODO(szager): Make the algorithm for adding/subtracting overflow:auto // scrollbars memoryless (crbug.com/625300). This client_width hack will
diff --git a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h index cf3c0bf..d3aa31c 100644 --- a/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h +++ b/third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h
@@ -335,6 +335,7 @@ bool ShouldPlaceVerticalScrollbarOnLeft() const override; int PageStep(ScrollbarOrientation) const override; ScrollBehavior ScrollBehaviorStyle() const override; + WebColorScheme UsedColorScheme() const override; cc::AnimationHost* GetCompositorAnimationHost() const override; CompositorAnimationTimeline* GetCompositorAnimationTimeline() const override; void GetTickmarks(Vector<IntRect>&) const override;
diff --git a/third_party/blink/renderer/core/paint/scrollable_area_painter.cc b/third_party/blink/renderer/core/paint/scrollable_area_painter.cc index d4361da..3f6d81c4 100644 --- a/third_party/blink/renderer/core/paint/scrollable_area_painter.cc +++ b/third_party/blink/renderer/core/paint/scrollable_area_painter.cc
@@ -226,7 +226,8 @@ } const auto& client = DisplayItemClientForCorner(); - theme->PaintScrollCorner(context, client, abs_rect); + theme->PaintScrollCorner(context, client, abs_rect, + GetScrollableArea().UsedColorScheme()); } PaintLayerScrollableArea& ScrollableAreaPainter::GetScrollableArea() const {
diff --git a/third_party/blink/renderer/core/scroll/scrollable_area.h b/third_party/blink/renderer/core/scroll/scrollable_area.h index 0ea6877..73ece98 100644 --- a/third_party/blink/renderer/core/scroll/scrollable_area.h +++ b/third_party/blink/renderer/core/scroll/scrollable_area.h
@@ -26,6 +26,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCROLL_SCROLLABLE_AREA_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_SCROLL_SCROLLABLE_AREA_H_ +#include "third_party/blink/public/platform/web_color_scheme.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/layout/geometry/physical_rect.h" #include "third_party/blink/renderer/core/scroll/scrollbar.h" @@ -364,6 +365,10 @@ return kScrollBehaviorInstant; } + virtual WebColorScheme UsedColorScheme() const { + return WebColorScheme::kLight; + } + // Subtracts space occupied by this ScrollableArea's scrollbars. // Does nothing if overlay scrollbars are enabled. IntSize ExcludeScrollbars(const IntSize&) const;
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.cc b/third_party/blink/renderer/core/scroll/scrollbar.cc index 410211a..7aecdafe 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar.cc +++ b/third_party/blink/renderer/core/scroll/scrollbar.cc
@@ -807,6 +807,10 @@ return false; } +WebColorScheme Scrollbar::UsedColorScheme() const { + return scrollable_area_->UsedColorScheme(); +} + STATIC_ASSERT_ENUM(kWebScrollbarOverlayColorThemeDark, kScrollbarOverlayColorThemeDark); STATIC_ASSERT_ENUM(kWebScrollbarOverlayColorThemeLight,
diff --git a/third_party/blink/renderer/core/scroll/scrollbar.h b/third_party/blink/renderer/core/scroll/scrollbar.h index 951a89f..3bbdbf6 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar.h +++ b/third_party/blink/renderer/core/scroll/scrollbar.h
@@ -26,6 +26,7 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SCROLL_SCROLLBAR_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_SCROLL_SCROLLBAR_H_ +#include "third_party/blink/public/platform/web_color_scheme.h" #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/platform/graphics/compositor_element_id.h" @@ -199,6 +200,8 @@ // is the element that owns our PaintLayerScrollableArea. Element* StyleSource() const { return style_source_.Get(); } + WebColorScheme UsedColorScheme() const; + virtual void Trace(blink::Visitor*); protected:
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc index 64bb992..f71b889 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme.cc +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.cc
@@ -190,7 +190,8 @@ void ScrollbarTheme::PaintScrollCorner( GraphicsContext& context, const DisplayItemClient& display_item_client, - const IntRect& corner_rect) { + const IntRect& corner_rect, + WebColorScheme color_scheme) { if (corner_rect.IsEmpty()) return; @@ -206,8 +207,7 @@ Platform::Current()->ThemeEngine()->Paint( context.Canvas(), WebThemeEngine::kPartScrollbarCorner, WebThemeEngine::kStateNormal, WebRect(corner_rect), nullptr, - WebColorScheme:: - kLight /* TODO(futhark): pass color scheme to scrollbars */); + color_scheme); #endif }
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme.h b/third_party/blink/renderer/core/scroll/scrollbar_theme.h index e7eb409b..a47d221 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme.h +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme.h
@@ -96,7 +96,8 @@ virtual void PaintScrollCorner(GraphicsContext&, const DisplayItemClient&, - const IntRect& corner_rect); + const IntRect& corner_rect, + WebColorScheme color_scheme); virtual void PaintTickmarks(GraphicsContext&, const Scrollbar&, const IntRect&);
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc index 609e3d51..3befd2a 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_aura.cc
@@ -263,9 +263,7 @@ scrollbar.Orientation() == kHorizontalScrollbar ? WebThemeEngine::kPartScrollbarHorizontalTrack : WebThemeEngine::kPartScrollbarVerticalTrack, - state, WebRect(rect), &extra_params, - WebColorScheme:: - kLight /* TODO(futhark): pass color scheme to scrollbar parts */); + state, WebRect(rect), &extra_params, scrollbar.UsedColorScheme()); } void ScrollbarThemeAura::PaintButton(GraphicsContext& gc, @@ -288,8 +286,7 @@ scrollbar.ContainerIsRightToLeft(); Platform::Current()->ThemeEngine()->Paint( gc.Canvas(), params.part, params.state, WebRect(rect), &extra_params, - WebColorScheme:: - kLight /* TODO(futhark): pass color scheme to scrollbar parts */); + scrollbar.UsedColorScheme()); } void ScrollbarThemeAura::PaintThumb(GraphicsContext& gc, @@ -315,9 +312,7 @@ scrollbar.Orientation() == kHorizontalScrollbar ? WebThemeEngine::kPartScrollbarHorizontalThumb : WebThemeEngine::kPartScrollbarVerticalThumb, - state, WebRect(rect), nullptr, - WebColorScheme:: - kLight /* TODO(futhark): pass color scheme to scrollbars */); + state, WebRect(rect), nullptr, scrollbar.UsedColorScheme()); } bool ScrollbarThemeAura::ShouldRepaintAllPartsOnInvalidation() const {
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.cc index 8922c77..83d2f6c 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.cc +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.cc
@@ -75,7 +75,8 @@ void ScrollbarThemeMock::PaintScrollCorner(GraphicsContext& context, const DisplayItemClient& scrollbar, - const IntRect& corner_rect) { + const IntRect& corner_rect, + WebColorScheme color_scheme) { if (DrawingRecorder::UseCachedDrawingIfPossible( context, scrollbar, DisplayItem::kScrollbarCorner)) return;
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.h b/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.h index 9f6e237a..d869f7865 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.h +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_mock.h
@@ -60,7 +60,8 @@ void PaintScrollCorner(GraphicsContext&, const DisplayItemClient&, - const IntRect& corner_rect) override; + const IntRect& corner_rect, + WebColorScheme color_scheme) override; int MinimumThumbLength(const Scrollbar&) override;
diff --git a/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc b/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc index e75a76d..f4421ea 100644 --- a/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc +++ b/third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.cc
@@ -196,8 +196,8 @@ canvas->scale(-1, 1); } - Platform::Current()->ThemeEngine()->Paint(canvas, part, state, WebRect(rect), - ¶ms, WebColorScheme::kLight); + Platform::Current()->ThemeEngine()->Paint( + canvas, part, state, WebRect(rect), ¶ms, scrollbar.UsedColorScheme()); if (scrollbar.IsLeftSideVerticalScrollbar()) canvas->restore();
diff --git a/third_party/blink/renderer/core/scroll/scrolling_test.cc b/third_party/blink/renderer/core/scroll/scrolling_test.cc index d02af8b..7f74325 100644 --- a/third_party/blink/renderer/core/scroll/scrolling_test.cc +++ b/third_party/blink/renderer/core/scroll/scrolling_test.cc
@@ -6,12 +6,15 @@ #include "base/test/bind_test_util.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/web/web_script_source.h" +#include "third_party/blink/renderer/core/css/css_style_declaration.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/frame/root_frame_viewport.h" #include "third_party/blink/renderer/core/frame/visual_viewport.h" +#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h" #include "third_party/blink/renderer/core/geometry/dom_rect.h" #include "third_party/blink/renderer/core/layout/layout_box.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" @@ -324,4 +327,151 @@ ASSERT_TRUE(finished); } +class ScrollInfacesUseCounterSimTest : public SimTest { + public: + // Reload the page, set direction and writing-mode, then check the initial + // useCounted status. + void Reset(const String& direction, const String& writing_mode) { + SimRequest request("https://example.com/test.html", "text/html"); + LoadURL("https://example.com/test.html"); + request.Complete(R"HTML( + <!DOCTYPE html> + <style> + #scroller { + width: 100px; + height: 100px; + overflow: scroll; + } + #content { + width: 300; + height: 300; + } + </style> + <div id="scroller"><div id="content"></div></div> + )HTML"); + auto& document = GetDocument(); + auto* style = document.getElementById("scroller")->style(); + style->setProperty(&document, "direction", direction, String(), + ASSERT_NO_EXCEPTION); + style->setProperty(&document, "writing-mode", writing_mode, String(), + ASSERT_NO_EXCEPTION); + Compositor().BeginFrame(); + EXPECT_FALSE(document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop)); + EXPECT_FALSE(document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive)); + } + + // Check if Element.scrollLeft/Top could trigger useCounter as expected. + void CheckScrollLeftOrTop(const String& command, bool exppected_use_counted) { + String scroll_command = + "document.querySelector('#scroller')." + command + ";"; + MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command)); + auto& document = GetDocument(); + EXPECT_EQ( + exppected_use_counted, + document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop)); + EXPECT_FALSE(document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive)); + } + + // Check if Element.setScrollLeft/Top could trigger useCounter as expected. + void CheckSetScrollLeftOrTop(const String& command, + bool exppected_use_counted) { + String scroll_command = + "document.querySelector('#scroller')." + command + " = -1;"; + MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command)); + auto& document = GetDocument(); + EXPECT_EQ( + exppected_use_counted, + document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop)); + EXPECT_FALSE(document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive)); + scroll_command = "document.querySelector('#scroller')." + command + " = 1;"; + MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command)); + EXPECT_EQ( + exppected_use_counted, + document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive)); + } + + // Check if Element.scrollTo/scroll could trigger useCounter as expected. + void CheckScrollTo(const String& command, bool exppected_use_counted) { + String scroll_command = + "document.querySelector('#scroller')." + command + "(-1, -1);"; + MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command)); + auto& document = GetDocument(); + EXPECT_EQ( + exppected_use_counted, + document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop)); + EXPECT_FALSE(document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive)); + scroll_command = + "document.querySelector('#scroller')." + command + "(1, 1);"; + MainFrame().ExecuteScriptAndReturnValue(WebScriptSource(scroll_command)); + EXPECT_EQ( + exppected_use_counted, + document.IsUseCounted( + WebFeature:: + kElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive)); + } +}; + +struct TestCase { + String direction; + String writingMode; + bool scrollLeftUseCounted; + bool scrollTopUseCounted; +}; + +TEST_F(ScrollInfacesUseCounterSimTest, ScrollTestAll) { + v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); + WebView().MainFrameWidget()->Resize(WebSize(800, 600)); + const Vector<TestCase> test_cases = { + {"ltr", "horizontal-tb", false, false}, + {"rtl", "horizontal-tb", true, false}, + {"ltr", "vertical-lr", false, false}, + {"rtl", "vertical-lr", false, true}, + {"ltr", "vertical-rl", true, false}, + {"rtl", "vertical-rl", true, true}, + }; + + for (const TestCase test_case : test_cases) { + Reset(test_case.direction, test_case.writingMode); + CheckScrollLeftOrTop("scrollLeft", test_case.scrollLeftUseCounted); + + Reset(test_case.direction, test_case.writingMode); + CheckSetScrollLeftOrTop("scrollLeft", test_case.scrollLeftUseCounted); + + Reset(test_case.direction, test_case.writingMode); + CheckScrollLeftOrTop("scrollTop", test_case.scrollTopUseCounted); + + Reset(test_case.direction, test_case.writingMode); + CheckSetScrollLeftOrTop("scrollTop", test_case.scrollTopUseCounted); + + bool expectedScrollUseCounted = + test_case.scrollLeftUseCounted || test_case.scrollTopUseCounted; + Reset(test_case.direction, test_case.writingMode); + CheckScrollTo("scrollTo", expectedScrollUseCounted); + + Reset(test_case.direction, test_case.writingMode); + CheckScrollTo("scroll", expectedScrollUseCounted); + + Reset(test_case.direction, test_case.writingMode); + CheckScrollTo("scrollBy", false); + } +} + } // namespace blink
diff --git a/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js b/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js index a6825b11..ba1c124 100644 --- a/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js +++ b/third_party/blink/renderer/devtools/front_end/color_picker/Spectrum.js
@@ -144,8 +144,10 @@ UI.ARIAUtils.markAsButton(paletteSwitcher); UI.ARIAUtils.setAccessibleName(paletteSwitcher, ls`Preview palettes`); paletteSwitcher.tabIndex = 0; - paletteSwitcher.addEventListener('click', this._togglePalettePanel.bind(this, true)); - paletteSwitcher.addEventListener('keydown', this._onTogglePaletteKeydown.bind(this)); + onInvokeElement(paletteSwitcher, event => { + this._togglePalettePanel(true); + event.consume(true); + }); this._deleteIconToolbar = new UI.Toolbar('delete-color-toolbar'); this._deleteButton = new UI.ToolbarButton('', 'largeicon-trash-bin'); @@ -249,16 +251,6 @@ /** * @param {!Event} event */ - _onTogglePaletteKeydown(event) { - if (isEnterKey(event) || event.key === ' ') { - this._togglePalettePanel(true); - event.consume(true); - } - } - - /** - * @param {!Event} event - */ _onPalettePanelKeydown(event) { if (isEscKey(event)) { this._togglePalettePanel(false); @@ -533,8 +525,10 @@ previewElement.appendChild(this._createPaletteColor(palette.colors[i], palette.colorNames[i])); for (; i < colorsPerPreviewRow; i++) previewElement.createChild('div', 'spectrum-palette-color empty-color'); - previewElement.addEventListener('click', this._paletteSelected.bind(this, palette)); - previewElement.addEventListener('keydown', this._onSelectedPaletteKeydown.bind(this, palette)); + onInvokeElement(previewElement, event => { + this._paletteSelected(palette); + event.consume(true); + }); return previewElement; } @@ -547,17 +541,6 @@ } /** - * @param {!ColorPicker.Spectrum.Palette} palette - * @param {!Event} event - */ - _onSelectedPaletteKeydown(palette, event) { - if (isEnterKey(event) || event.key === ' ') { - this._paletteSelected(palette); - event.consume(true); - } - } - - /** * @param {boolean=} force */ _resizeForSelectedPalette(force) {
diff --git a/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js b/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js index 95a7d15..7367b02 100644 --- a/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js +++ b/third_party/blink/renderer/devtools/front_end/console/ConsolePinPane.js
@@ -101,11 +101,7 @@ constructor(expression, pinPane) { super(); const deletePinIcon = UI.Icon.create('smallicon-cross', 'console-delete-pin'); - deletePinIcon.addEventListener('click', () => pinPane._removePin(this)); - deletePinIcon.addEventListener('keydown', event => { - if (isEnterKey(event) || event.key === ' ') - pinPane._removePin(this); - }); + onInvokeElement(deletePinIcon, () => pinPane._removePin(this)); deletePinIcon.tabIndex = 0; UI.ARIAUtils.setAccessibleName(deletePinIcon, ls`Remove expression`); UI.ARIAUtils.markAsButton(deletePinIcon);
diff --git a/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js b/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js index 2574dec4..ff10a8d 100644 --- a/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js +++ b/third_party/blink/renderer/devtools/front_end/dom_extension/DOMExtension.js
@@ -811,6 +811,18 @@ }; /** + * @param {!Element} element + * @param {function(!Event)} callback + */ +function onInvokeElement(element, callback) { + element.addEventListener('keydown', event => { + if (isEnterOrSpaceKey(event)) + callback(event); + }); + element.addEventListener('click', event => callback(event)); +} + +/** * @param {!Event} event * @return {boolean} */ @@ -823,6 +835,14 @@ * @param {!Event} event * @return {boolean} */ +function isEnterOrSpaceKey(event) { + return isEnterKey(event) || event.key === ' '; +} + +/** + * @param {!Event} event + * @return {boolean} + */ function isEscKey(event) { return event.keyCode === 27; }
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js b/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js index eccad34..036398d 100644 --- a/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js +++ b/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js
@@ -35,15 +35,12 @@ this._otherSWFilter.setAttribute('tabindex', 0); this._otherSWFilter.setAttribute('role', 'switch'); this._otherSWFilter.setAttribute('aria-checked', false); - this._otherSWFilter.addEventListener('keydown', event => { - if (event.target !== this._otherSWFilter) - return; - if (isEnterKey(event) || event.key === ' ') - this._toggleFilter(); - }); const filterLabel = this._otherSWFilter.createChild('label', 'service-worker-filter-label'); filterLabel.textContent = Common.UIString('Service workers from other origins'); - filterLabel.addEventListener('click', () => this._toggleFilter()); + onInvokeElement(this._otherSWFilter, event => { + if (event.target === this._otherSWFilter || event.target === filterLabel) + this._toggleFilter(); + }); const toolbar = new UI.Toolbar('service-worker-filter-toolbar', this._otherSWFilter); this._filter = new UI.ToolbarInput(ls`Filter service worker`, 1); @@ -440,11 +437,7 @@ errorsLabel.classList.add('link'); errorsLabel.tabIndex = 0; UI.ARIAUtils.setAccessibleName(errorsLabel, ls`${this._registration.errors.length} registration errors`); - errorsLabel.addEventListener('click', () => Common.console.show()); - errorsLabel.addEventListener('keydown', event => { - if (isEnterKey(event) || event.key === ' ') - Common.console.show(); - }); + onInvokeElement(errorsLabel, () => Common.console.show()); name.appendChild(errorsLabel); } this._sourceField.createChild('div', 'report-field-value-subtitle').textContent =
diff --git a/third_party/blink/renderer/devtools/front_end/ui/FilterBar.js b/third_party/blink/renderer/devtools/front_end/ui/FilterBar.js index 8393d077..85b416d9 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/FilterBar.js +++ b/third_party/blink/renderer/devtools/front_end/ui/FilterBar.js
@@ -387,7 +387,7 @@ event.consume(true); return; } - } else if (!(event.key === ' ' || isEnterKey(event))) { + } else if (!isEnterOrSpaceKey(event)) { return; }
diff --git a/third_party/blink/renderer/devtools/front_end/ui/View.js b/third_party/blink/renderer/devtools/front_end/ui/View.js index ead3c4e0..4dbf3413 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/View.js +++ b/third_party/blink/renderer/devtools/front_end/ui/View.js
@@ -564,7 +564,7 @@ * @param {!Event} event */ _onTitleKeyDown(event) { - if (isEnterKey(event) || event.keyCode === UI.KeyboardShortcut.Keys.Space.code) { + if (isEnterOrSpaceKey(event)) { this._toggleExpanded(); } else if (event.key === 'ArrowLeft') { this._collapse();
diff --git a/third_party/blink/renderer/devtools/front_end/ui/XLink.js b/third_party/blink/renderer/devtools/front_end/ui/XLink.js index a29a72af..6f1aa1a 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/XLink.js +++ b/third_party/blink/renderer/devtools/front_end/ui/XLink.js
@@ -42,10 +42,10 @@ InspectorFrontendHost.openInNewTab(/** @type {string} */ (this._href)); }; this._onKeyDown = event => { - if (event.key !== ' ' && !isEnterKey(event)) - return; - event.consume(true); - InspectorFrontendHost.openInNewTab(/** @type {string} */ (this._href)); + if (isEnterOrSpaceKey(event)) { + event.consume(true); + InspectorFrontendHost.openInNewTab(/** @type {string} */ (this._href)); + } }; }
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc index 6685c58..8d6c41e1 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.cc +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.cc
@@ -227,6 +227,20 @@ return scope->Url(); } +scoped_refptr<SecurityOrigin> DefaultTopFrameOrigin( + ExecutionContext* execution_context) { + DCHECK(execution_context); + + if (auto* document = DynamicTo<Document>(execution_context)) { + // Can we avoid the copy? TopFrameOrigin is returned as const& but we need + // a scoped_refptr. + return document->TopFrameOrigin()->IsolatedCopy(); + } + + auto* scope = To<ServiceWorkerGlobalScope>(execution_context); + return scope->GetSecurityOrigin()->IsolatedCopy(); +} + } // namespace CookieStore::~CookieStore() = default; @@ -449,7 +463,8 @@ subscription_backend_(std::move(subscription_backend)), change_listener_binding_(this), default_cookie_url_(DefaultCookieURL(execution_context)), - default_site_for_cookies_(DefaultSiteForCookies(execution_context)) { + default_site_for_cookies_(DefaultSiteForCookies(execution_context)), + default_top_frame_origin_(DefaultTopFrameOrigin(execution_context)) { DCHECK(backend_); } @@ -473,7 +488,7 @@ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); backend_->GetAllForUrl( - default_cookie_url_, default_site_for_cookies_, + default_cookie_url_, default_site_for_cookies_, default_top_frame_origin_, std::move(backend_options), WTF::Bind(backend_result_converter, WrapPersistent(resolver))); return resolver->Promise(); @@ -535,7 +550,7 @@ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); backend_->SetCanonicalCookie( std::move(canonical_cookie.value()), default_cookie_url_, - default_site_for_cookies_, + default_site_for_cookies_, default_top_frame_origin_, WTF::Bind(&CookieStore::OnSetCanonicalCookieResult, WrapPersistent(resolver))); return resolver->Promise(); @@ -612,6 +627,7 @@ change_listener_binding_.Bind( mojo::MakeRequest(&change_listener, task_runner), task_runner); backend_->AddChangeListener(default_cookie_url_, default_site_for_cookies_, + default_top_frame_origin_, std::move(change_listener), {}); }
diff --git a/third_party/blink/renderer/modules/cookie_store/cookie_store.h b/third_party/blink/renderer/modules/cookie_store/cookie_store.h index 3bb8eed6..f055679 100644 --- a/third_party/blink/renderer/modules/cookie_store/cookie_store.h +++ b/third_party/blink/renderer/modules/cookie_store/cookie_store.h
@@ -169,6 +169,9 @@ // The RFC 6265bis "site for cookies" for this store's ExecutionContext. const KURL default_site_for_cookies_; + + // The context in which cookies are accessed. + const scoped_refptr<SecurityOrigin> default_top_frame_origin_; }; } // namespace blink
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc index 2aaecb0..5d46a342 100644 --- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc +++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.cc
@@ -181,26 +181,14 @@ pause_after_download_state_ = kDoPauseAfterDownload; devtools_worker_token_ = data.devtools_worker_token; - // |loader_factory| is null since all loads for new scripts go through - // ServiceWorkerNetworkProviderForServiceWorker::script_loader_factory() - // rather than the shadow page's loader. - shadow_page_ = std::make_unique<WorkerShadowPage>( - this, nullptr /* loader_factory */, - std::move(worker_start_data_.privacy_preferences)); - wait_for_debugger_mode_ = worker_start_data_.wait_for_debugger_mode; - shadow_page_->Initialize(worker_start_data_.script_url); + StartWorkerThread(); } void WebEmbeddedWorkerImpl::TerminateWorkerContext() { if (asked_to_terminate_) return; asked_to_terminate_ = true; - if (!shadow_page_->WasInitialized()) { - // This deletes 'this'. - worker_context_client_->WorkerContextFailedToStartOnInitiatorThread(); - return; - } if (!worker_thread_) { // The worker thread has not been created yet if the worker is asked to // terminate during waiting for debugger or paused after download. @@ -221,21 +209,12 @@ void WebEmbeddedWorkerImpl::AddMessageToConsole( const WebConsoleMessage& message) { - shadow_page_->GetDocument()->AddConsoleMessage(ConsoleMessage::Create( - mojom::ConsoleMessageSource::kOther, message.level, message.text, - std::make_unique<SourceLocation>(message.url, message.line_number, - message.column_number, nullptr))); -} - -void WebEmbeddedWorkerImpl::OnShadowPageInitialized() { - DCHECK(!asked_to_terminate_); - - // This shadow page's address space will be used for creating outside - // FetchClientSettingsObject. - shadow_page_->GetDocument()->SetAddressSpace( - worker_start_data_.address_space); - - StartWorkerThread(); + // TODO(bashi): Remove this method, or consider to have alternative. + // This method was used to show messages (e.g. reporting force update) on the + // "parent" DevTools console. The parent was a DevTools session which is + // associated with a shadow page. However, we removed shadow page + // dependency from service workers. Unlike dedicated workers there is no + // parent context so there is no drop-in replacement. } void WebEmbeddedWorkerImpl::StartWorkerThread() {
diff --git a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h index 734b269..9d39352 100644 --- a/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h +++ b/third_party/blink/renderer/modules/exported/web_embedded_worker_impl.h
@@ -39,7 +39,6 @@ #include "third_party/blink/public/mojom/cache_storage/cache_storage.mojom-blink.h" #include "third_party/blink/public/web/web_embedded_worker.h" #include "third_party/blink/public/web/web_embedded_worker_start_data.h" -#include "third_party/blink/renderer/core/exported/worker_shadow_page.h" #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h" #include "third_party/blink/renderer/core/workers/worker_clients.h" #include "third_party/blink/renderer/modules/modules_export.h" @@ -59,9 +58,7 @@ // start the worker thread off the main thread. This means that // WebEmbeddedWorkerImpl shouldn't create garbage-collected objects during // worker startup. See https://crbug.com/988335 for details. -class MODULES_EXPORT WebEmbeddedWorkerImpl final - : public WebEmbeddedWorker, - public WorkerShadowPage::Client { +class MODULES_EXPORT WebEmbeddedWorkerImpl final : public WebEmbeddedWorker { public: WebEmbeddedWorkerImpl( WebServiceWorkerContextClient*, @@ -78,12 +75,6 @@ void ResumeAfterDownload() override; void AddMessageToConsole(const WebConsoleMessage&) override; - // WorkerShadowPage::Client overrides. - void OnShadowPageInitialized() override; - WebLocalFrameClient::AppCacheType GetAppCacheType() override { - return WebLocalFrameClient::AppCacheType::kAppCacheForNone; - } - static std::unique_ptr<WebEmbeddedWorkerImpl> CreateForTesting( WebServiceWorkerContextClient*, std::unique_ptr<ServiceWorkerInstalledScriptsManager>); @@ -111,8 +102,6 @@ std::unique_ptr<ServiceWorkerThread> worker_thread_; - std::unique_ptr<WorkerShadowPage> shadow_page_; - bool asked_to_terminate_ = false; // TODO(bashi): Remove. This is no longer used.
diff --git a/third_party/blink/renderer/modules/nfc/nfc_constants.cc b/third_party/blink/renderer/modules/nfc/nfc_constants.cc index e5313a81..13b9f96 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_constants.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_constants.cc
@@ -16,9 +16,10 @@ const char kNfcCharSetUTF8[] = ";charset=UTF-8"; // Error messages. -const char kNfcNotSupported[] = "NFC operation not supported."; -const char kNfcNotReadable[] = "No NFC adapter or cannot establish connection."; const char kNfcNotAllowed[] = "NFC operation not allowed."; +const char kNfcNotSupported[] = + "No NFC adapter or cannot establish connection."; +const char kNfcNotReadable[] = "NFC is not enabled."; const char kNfcTextRecordTypeError[] = "The data for 'text' NDEFRecords must be of String or UnrestrctedDouble."; const char kNfcSetIdError[] = "Cannot set WebNFC Id.";
diff --git a/third_party/blink/renderer/modules/nfc/nfc_constants.h b/third_party/blink/renderer/modules/nfc/nfc_constants.h index 3a25c9dc..d300dea 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_constants.h +++ b/third_party/blink/renderer/modules/nfc/nfc_constants.h
@@ -24,9 +24,9 @@ extern const char kNfcCharSetUTF8[]; // Error messages. +extern const char kNfcNotAllowed[]; extern const char kNfcNotSupported[]; extern const char kNfcNotReadable[]; -extern const char kNfcNotAllowed[]; extern const char kNfcTextRecordTypeError[]; extern const char kNfcSetIdError[]; extern const char kNfcTextRecordMediaTypeError[];
diff --git a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc index 28ac909..956c04ab 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_proxy.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_proxy.cc
@@ -209,7 +209,7 @@ for (auto& pair : readers) { // The reader may call StopReading() to remove itself from |readers_| when // handling the error. - pair.key->OnError(device::mojom::blink::NFCErrorType::NOT_READABLE); + pair.key->OnError(device::mojom::blink::NFCErrorType::NOT_SUPPORTED); } // Each connection maintains its own watch ID numbering, so reset to 1 on
diff --git a/third_party/blink/renderer/modules/nfc/nfc_writer.cc b/third_party/blink/renderer/modules/nfc/nfc_writer.cc index cf0b96c..c5b7af5a 100644 --- a/third_party/blink/renderer/modules/nfc/nfc_writer.cc +++ b/third_party/blink/renderer/modules/nfc/nfc_writer.cc
@@ -116,7 +116,7 @@ // default error. for (ScriptPromiseResolver* resolver : requests_) { resolver->Reject(NFCErrorTypeToDOMException( - device::mojom::blink::NFCErrorType::NOT_READABLE)); + device::mojom::blink::NFCErrorType::NOT_SUPPORTED)); } requests_.clear(); }
diff --git a/third_party/blink/renderer/platform/graphics/color_behavior.h b/third_party/blink/renderer/platform/graphics/color_behavior.h index ce04f84..7d3c6ab9 100644 --- a/third_party/blink/renderer/platform/graphics/color_behavior.h +++ b/third_party/blink/renderer/platform/graphics/color_behavior.h
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/platform/platform_export.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h" #include "ui/gfx/color_space.h" namespace blink { @@ -49,4 +50,15 @@ } // namespace blink +namespace WTF { + +template <> +struct CrossThreadCopier<blink::ColorBehavior> { + STATIC_ONLY(CrossThreadCopier); + using Type = blink::ColorBehavior; + static Type Copy(Type pointer) { return pointer; } +}; + +} // namespace WTF + #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_GRAPHICS_COLOR_BEHAVIOR_H_
diff --git a/third_party/blink/renderer/platform/instrumentation/OWNERS b/third_party/blink/renderer/platform/instrumentation/OWNERS index 001a7e7..ed174f35 100644 --- a/third_party/blink/renderer/platform/instrumentation/OWNERS +++ b/third_party/blink/renderer/platform/instrumentation/OWNERS
@@ -1,4 +1,7 @@ +eseckler@chromium.org +oysteine@chromium.org primiano@chromium.org +skyostil@chromium.org # TEAM: tracing@chromium.org # COMPONENT: Speed>Tracing
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc index 2fa3afe..729de4b 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl.cc
@@ -401,10 +401,12 @@ base::Optional<QueueTraits> FrameSchedulerImpl::CreateQueueTraitsForTaskType( TaskType type) { // TODO(haraken): Optimize the mapping from TaskTypes to task runners. + // TODO(sreejakshetty): Clean up the PrioritisationType QueueTrait and + // QueueType for kInternalContinueScriptLoading and kInternalContentCapture. switch (type) { - // kInternalContentCapture uses BestEffortTaskQueue and is handled - // separately. case TaskType::kInternalContentCapture: + return ThrottleableTaskQueueTraits().SetPrioritisationType( + QueueTraits::PrioritisationType::kBestEffort); case TaskType::kJavascriptTimer: return ThrottleableTaskQueueTraits(); case TaskType::kInternalLoading: @@ -455,13 +457,17 @@ case TaskType::kInternalMediaRealTime: case TaskType::kInternalUserInteraction: case TaskType::kInternalIntersectionObserver: - case TaskType::kInternalContinueScriptLoading: return PausableTaskQueueTraits(); + case TaskType::kInternalContinueScriptLoading: + return PausableTaskQueueTraits().SetPrioritisationType( + QueueTraits::PrioritisationType::kVeryHigh); case TaskType::kDatabaseAccess: - if (base::FeatureList::IsEnabled(kHighPriorityDatabaseTaskType)) - return PausableTaskQueueTraits().SetIsHighPriority(true); - else + if (base::FeatureList::IsEnabled(kHighPriorityDatabaseTaskType)) { + return PausableTaskQueueTraits().SetPrioritisationType( + QueueTraits::PrioritisationType::kHigh); + } else { return PausableTaskQueueTraits(); + } case TaskType::kInternalFreezableIPC: return FreezableTaskQueueTraits(); case TaskType::kInternalIPC: @@ -520,16 +526,12 @@ scoped_refptr<MainThreadTaskQueue> FrameSchedulerImpl::GetTaskQueue( TaskType type) { switch (type) { - case TaskType::kInternalContinueScriptLoading: - return frame_task_queue_controller_->VeryHighPriorityTaskQueue(); case TaskType::kInternalLoading: case TaskType::kNetworking: case TaskType::kNetworkingWithURLLoaderAnnotation: return frame_task_queue_controller_->LoadingTaskQueue(); case TaskType::kNetworkingControl: return frame_task_queue_controller_->LoadingControlTaskQueue(); - case TaskType::kInternalContentCapture: - return frame_task_queue_controller_->BestEffortTaskQueue(); default: // Non-loading task queue. DCHECK_LT(static_cast<size_t>(type),
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc index 4abc5a36..a8fc350f 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_scheduler_impl_unittest.cc
@@ -1944,7 +1944,8 @@ base::Unretained(&counter))); auto da_queue = GetTaskQueue(TaskType::kDatabaseAccess); - EXPECT_EQ(da_queue->GetQueueTraits().is_high_priority, false); + EXPECT_EQ(da_queue->GetQueueTraits().prioritisation_type, + MainThreadTaskQueue::QueueTraits::PrioritisationType::kRegular); EXPECT_EQ(da_queue->GetQueuePriority(), TaskQueue::QueuePriority::kNormalPriority); da_queue->task_runner()->PostTask( @@ -1984,7 +1985,8 @@ base::Unretained(&counter))); auto da_queue = GetTaskQueue(TaskType::kDatabaseAccess); - EXPECT_EQ(da_queue->GetQueueTraits().is_high_priority, true); + EXPECT_EQ(da_queue->GetQueueTraits().prioritisation_type, + MainThreadTaskQueue::QueueTraits::PrioritisationType::kHigh); EXPECT_EQ(da_queue->GetQueuePriority(), TaskQueue::QueuePriority::kHighPriority); da_queue->task_runner()->PostTask(
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc index 131e9731..a9109caf 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.cc
@@ -55,30 +55,6 @@ } scoped_refptr<MainThreadTaskQueue> -FrameTaskQueueController::BestEffortTaskQueue() { - if (!best_effort_task_queue_) { - best_effort_task_queue_ = main_thread_scheduler_impl_->NewTaskQueue( - MainThreadTaskQueue::QueueCreationParams( - MainThreadTaskQueue::QueueType::kIdle) - .SetFrameScheduler(frame_scheduler_impl_) - .SetFixedPriority(TaskQueue::QueuePriority::kBestEffortPriority)); - TaskQueueCreated(best_effort_task_queue_); - } - return best_effort_task_queue_; -} - -scoped_refptr<MainThreadTaskQueue> -FrameTaskQueueController::VeryHighPriorityTaskQueue() { - if (!very_high_priority_task_queue_) { - very_high_priority_task_queue_ = main_thread_scheduler_impl_->NewTaskQueue( - MainThreadTaskQueue::QueueCreationParams( - MainThreadTaskQueue::QueueType::kDefault) - .SetFixedPriority(TaskQueue::QueuePriority::kVeryHighPriority)); - } - return very_high_priority_task_queue_; -} - -scoped_refptr<MainThreadTaskQueue> FrameTaskQueueController::NonLoadingTaskQueue( MainThreadTaskQueue::QueueTraits queue_traits) { if (!non_loading_task_queues_.Contains(queue_traits.Key())) @@ -164,9 +140,21 @@ .SetFreezeWhenKeepActive(queue_traits.can_be_throttled) .SetFrameScheduler(frame_scheduler_impl_); - if (queue_traits.is_high_priority) { - queue_creation_params = queue_creation_params.SetFixedPriority( + switch (queue_traits.prioritisation_type) { + case QueueTraits::PrioritisationType::kVeryHigh: + queue_creation_params = queue_creation_params.SetFixedPriority( + TaskQueue::QueuePriority::kVeryHighPriority); + break; + case QueueTraits::PrioritisationType::kHigh: + queue_creation_params = queue_creation_params.SetFixedPriority( TaskQueue::QueuePriority::kHighPriority); + break; + case QueueTraits::PrioritisationType::kBestEffort: + queue_creation_params = queue_creation_params.SetFixedPriority( + TaskQueue::QueuePriority::kBestEffortPriority); + break; + default: + break; } scoped_refptr<MainThreadTaskQueue> task_queue =
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h index db53837a..96b503d4 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller.h
@@ -73,13 +73,6 @@ // Return the loading control task queue and create it if it doesn't exist. scoped_refptr<MainThreadTaskQueue> LoadingControlTaskQueue(); - // Return the best effort task queue and create it if it doesn't exist. - scoped_refptr<MainThreadTaskQueue> BestEffortTaskQueue(); - - // Return the continue script loading task queue and create it if it doesn't - // exist. - scoped_refptr<MainThreadTaskQueue> VeryHighPriorityTaskQueue(); - // Return the non-loading task queue associated with the given queue traits, // and created it if it doesn't exist. scoped_refptr<MainThreadTaskQueue> NonLoadingTaskQueue( @@ -114,7 +107,9 @@ friend class FrameTaskQueueControllerTest; void CreateLoadingTaskQueue(); + void CreateLoadingControlTaskQueue(); + void CreateNonLoadingTaskQueue(MainThreadTaskQueue::QueueTraits); void TaskQueueCreated(const scoped_refptr<MainThreadTaskQueue>&); @@ -134,12 +129,9 @@ // those queue traits can be the same as non-loading queues. This prevents us // from being able to the find right task queue by queue traits alone. scoped_refptr<MainThreadTaskQueue> loading_task_queue_; + scoped_refptr<MainThreadTaskQueue> loading_control_task_queue_; - scoped_refptr<MainThreadTaskQueue> best_effort_task_queue_; - - scoped_refptr<MainThreadTaskQueue> very_high_priority_task_queue_; - using NonLoadingTaskQueueMap = WTF::HashMap<MainThreadTaskQueue::QueueTraitsKeyType, scoped_refptr<MainThreadTaskQueue>>;
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc index 78068c08..abc2179 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc +++ b/third_party/blink/renderer/platform/scheduler/main_thread/frame_task_queue_controller_unittest.cc
@@ -162,12 +162,6 @@ all_task_queues.insert(task_queue.get(), QueueCheckResult::kDidNotSeeQueue); EXPECT_EQ(all_task_queues.size(), task_queue_created_count()); - // Add best effort task queue. - task_queue = frame_task_queue_controller_->BestEffortTaskQueue(); - EXPECT_FALSE(all_task_queues.Contains(task_queue)); - all_task_queues.insert(task_queue.get(), QueueCheckResult::kDidNotSeeQueue); - EXPECT_EQ(all_task_queues.size(), task_queue_created_count()); - // Verify that we get all of the queues that we added, and only those queues. EXPECT_EQ(all_task_queues.size(), frame_task_queue_controller_->GetAllTaskQueuesAndVoters().size()); @@ -245,36 +239,6 @@ frame_task_queue_controller_->GetAllTaskQueuesAndVoters().size()); } -TEST_F(FrameTaskQueueControllerTest, AddAndRetrieveAllNonLoadingTaskQueues) { - // Create queues for all combination of queue traits for all combinations of - // the 4 QueueTraits bits. - WTF::HashSet<scoped_refptr<MainThreadTaskQueue>> all_task_queues; - constexpr size_t kTotalUniqueQueueTraits = 1 << 4; - for (size_t i = 0; i < kTotalUniqueQueueTraits; i++) { - MainThreadTaskQueue::QueueTraits queue_traits = - QueueTraits() - .SetCanBeThrottled(!!(i & 1 << 0)) - .SetCanBeDeferred(!!(i & 1 << 1)) - .SetCanBeFrozen(!!(i & 1 << 2)) - .SetCanBePaused(!!(i & 1 << 3)); - scoped_refptr<MainThreadTaskQueue> task_queue = - frame_task_queue_controller_->NonLoadingTaskQueue(queue_traits); - EXPECT_FALSE(all_task_queues.Contains(task_queue)); - all_task_queues.insert(task_queue); - EXPECT_EQ(task_queue->GetQueueTraits(), queue_traits); - } - // Make sure we get the same queues back, with matching QueueTraits. - EXPECT_EQ(all_task_queues.size(), kTotalUniqueQueueTraits); - for (const auto& task_queue : all_task_queues) { - scoped_refptr<MainThreadTaskQueue> returned_task_queue = - frame_task_queue_controller_->NonLoadingTaskQueue( - task_queue->GetQueueTraits()); - EXPECT_EQ(task_queue->GetQueueTraits(), - returned_task_queue->GetQueueTraits()); - EXPECT_TRUE(task_queue == returned_task_queue); - } -} - TEST_F(FrameTaskQueueControllerTest, NonWebSchedulingTaskQueueWebSchedulingPriorityNullopt) { scoped_refptr<MainThreadTaskQueue> task_queue = @@ -342,5 +306,54 @@ EXPECT_NE(task_queue1.get(), task_queue2.get()); } +class TaskQueueCreationFromQueueTraitsTest : + public FrameTaskQueueControllerTest, + public testing::WithParamInterface<QueueTraits::PrioritisationType> {}; + +INSTANTIATE_TEST_SUITE_P(, + TaskQueueCreationFromQueueTraitsTest, + ::testing::Values( + QueueTraits::PrioritisationType::kVeryHigh, + QueueTraits::PrioritisationType::kHigh, + QueueTraits::PrioritisationType::kBestEffort, + QueueTraits::PrioritisationType::kRegular)); + +TEST_P(TaskQueueCreationFromQueueTraitsTest, + AddAndRetrieveAllNonLoadingTaskQueues) { + // Create queues for all combination of queue traits for all combinations of + // the 6 QueueTraits bits with different PrioritisationTypes. + WTF::HashSet<scoped_refptr<MainThreadTaskQueue>> all_task_queues; + constexpr size_t kTotalUniqueQueueTraits = 1 << 6; + for (size_t i = 0; i < kTotalUniqueQueueTraits; i++) { + QueueTraits::PrioritisationType prioritisation_type = GetParam(); + MainThreadTaskQueue::QueueTraits queue_traits = + QueueTraits() + .SetCanBeThrottled(!!(i & 1 << 0)) + .SetCanBeDeferred(!!(i & 1 << 1)) + .SetCanBeFrozen(!!(i & 1 << 2)) + .SetCanBePaused(!!(i & 1 << 3)) + .SetCanRunInBackground(!!(i & 1 << 4)) + .SetShouldUseVirtualTime(!!(i & 1 << 5)) + .SetPrioritisationType(prioritisation_type); + scoped_refptr<MainThreadTaskQueue> task_queue = + frame_task_queue_controller_->NonLoadingTaskQueue(queue_traits); + EXPECT_FALSE(all_task_queues.Contains(task_queue)); + all_task_queues.insert(task_queue); + EXPECT_EQ(task_queue->GetQueueTraits(), queue_traits); + EXPECT_EQ(task_queue->GetQueueTraits().prioritisation_type, + prioritisation_type); + } + // Make sure we get the same queues back, with matching QueueTraits. + EXPECT_EQ(all_task_queues.size(), kTotalUniqueQueueTraits); + for (const auto& task_queue : all_task_queues) { + scoped_refptr<MainThreadTaskQueue> returned_task_queue = + frame_task_queue_controller_->NonLoadingTaskQueue( + task_queue->GetQueueTraits()); + EXPECT_EQ(task_queue->GetQueueTraits(), + returned_task_queue->GetQueueTraits()); + EXPECT_TRUE(task_queue == returned_task_queue); + } +} + } // namespace scheduler } // namespace blink
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h index c7d2c20..e98ee7aa 100644 --- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h +++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_task_queue.h
@@ -118,8 +118,28 @@ can_be_paused(false), can_be_frozen(false), can_run_in_background(true), - should_use_virtual_time(false), - is_high_priority(false) {} + should_use_virtual_time(false) {} + + // Separate enum class for handling prioritisation decisions in task queues. + enum class PrioritisationType { + kVeryHigh = 0, + kHigh = 1, + kBestEffort = 2, + kRegular = 3, + + kCount = 4 + }; + + // kPrioritisationTypeWidthBits is the number of bits required + // for PrioritisationType::kCount - 1, which is the number of bits needed + // to represent |prioritisation_type| in QueueTraitKeyType. + // We need to update it whenever there is a change in + // PrioritisationType::kCount. + // TODO(sreejakshetty) make the number of bits calculation automated. + static constexpr int kPrioritisationTypeWidthBits = 2; + static_assert(static_cast<int>(PrioritisationType::kCount) <= + (1 << kPrioritisationTypeWidthBits), + "Wrong Instanstiation for kPrioritisationTypeWidthBits"); QueueTraits(const QueueTraits&) = default; @@ -153,8 +173,8 @@ return *this; } - QueueTraits SetIsHighPriority(bool value) { - is_high_priority = value; + QueueTraits SetPrioritisationType(PrioritisationType type) { + prioritisation_type = type; return *this; } @@ -165,20 +185,23 @@ can_be_frozen == other.can_be_frozen && can_run_in_background == other.can_run_in_background && should_use_virtual_time == other.should_use_virtual_time && - is_high_priority == other.is_high_priority; + prioritisation_type == other.prioritisation_type; } // Return a key suitable for WTF::HashMap. QueueTraitsKeyType Key() const { - // Start at 1; 0 and -1 are used for empty/deleted values. - int key = 1 << 0; - key |= can_be_deferred << 1; - key |= can_be_throttled << 2; - key |= can_be_paused << 3; - key |= can_be_frozen << 4; - key |= can_run_in_background << 5; - key |= should_use_virtual_time << 6; - key |= is_high_priority << 7; + // offset for shifting bits to compute |key|. + // |key| starts at 1 since 0 and -1 are used for empty/deleted values. + int offset = 0; + int key = 1 << (offset++); + key |= can_be_deferred << (offset++); + key |= can_be_throttled << (offset++); + key |= can_be_paused << (offset++); + key |= can_be_frozen << (offset++); + key |= can_run_in_background << (offset++); + key |= should_use_virtual_time << (offset++); + key |= static_cast<int>(prioritisation_type) << offset; + offset += kPrioritisationTypeWidthBits; return key; } @@ -188,7 +211,7 @@ bool can_be_frozen : 1; bool can_run_in_background : 1; bool should_use_virtual_time : 1; - bool is_high_priority : 1; + PrioritisationType prioritisation_type = PrioritisationType::kRegular; }; struct QueueCreationParams {
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.cc b/third_party/blink/renderer/platform/weborigin/security_origin.cc index aac0c777..7c0b0d42 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin.cc +++ b/third_party/blink/renderer/platform/weborigin/security_origin.cc
@@ -159,7 +159,8 @@ const SecurityOrigin* precursor) : nonce_if_opaque_(nonce), precursor_origin_(precursor) {} -SecurityOrigin::SecurityOrigin(const SecurityOrigin* other) +SecurityOrigin::SecurityOrigin(const SecurityOrigin* other, + ConstructIsolatedCopy) : protocol_(other->protocol_.IsolatedCopy()), host_(other->host_.IsolatedCopy()), domain_(other->domain_.IsolatedCopy()), @@ -174,10 +175,30 @@ is_opaque_origin_potentially_trustworthy_( other->is_opaque_origin_potentially_trustworthy_), cross_agent_cluster_access_(other->cross_agent_cluster_access_), + agent_cluster_id_(other->agent_cluster_id_), precursor_origin_(other->precursor_origin_ ? other->precursor_origin_->IsolatedCopy() : nullptr) {} +SecurityOrigin::SecurityOrigin(const SecurityOrigin* other, + ConstructSameThreadCopy) + : protocol_(other->protocol_), + host_(other->host_), + domain_(other->domain_), + port_(other->port_), + effective_port_(other->effective_port_), + nonce_if_opaque_(other->nonce_if_opaque_), + universal_access_(other->universal_access_), + domain_was_set_in_dom_(other->domain_was_set_in_dom_), + can_load_local_resources_(other->can_load_local_resources_), + block_local_access_from_local_origin_( + other->block_local_access_from_local_origin_), + is_opaque_origin_potentially_trustworthy_( + other->is_opaque_origin_potentially_trustworthy_), + cross_agent_cluster_access_(other->cross_agent_cluster_access_), + agent_cluster_id_(other->agent_cluster_id_), + precursor_origin_(other->precursor_origin_) {} + scoped_refptr<SecurityOrigin> SecurityOrigin::CreateWithReferenceOrigin( const KURL& url, const SecurityOrigin* reference_origin) { @@ -263,7 +284,8 @@ } scoped_refptr<SecurityOrigin> SecurityOrigin::IsolatedCopy() const { - return base::AdoptRef(new SecurityOrigin(this)); + return base::AdoptRef(new SecurityOrigin( + this, ConstructIsolatedCopy::kConstructIsolatedCopyBit)); } void SecurityOrigin::SetDomainFromDOM(const String& new_domain) { @@ -546,11 +568,16 @@ } String SecurityOrigin::ToTokenForFastCheck() const { + CHECK(!agent_cluster_id_.is_empty()); if (SerializesAsNull()) return String(); StringBuilder result; BuildRawString(result); + // Append the agent cluster id to the generated token to prevent + // access from two contexts that have the same origin but are + // in different agent clusters. + result.Append(agent_cluster_id_.ToString().c_str()); return result.ToString(); } @@ -662,4 +689,14 @@ return String::FromUTF8(canon_output.data(), canon_output.length()); } +scoped_refptr<SecurityOrigin> SecurityOrigin::GetOriginForAgentCluster( + const base::UnguessableToken& agent_cluster_id) { + if (agent_cluster_id_ == agent_cluster_id) + return this; + auto result = base::AdoptRef(new SecurityOrigin( + this, ConstructSameThreadCopy::kConstructSameThreadCopyBit)); + result->agent_cluster_id_ = agent_cluster_id; + return result; +} + } // namespace blink
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin.h b/third_party/blink/renderer/platform/weborigin/security_origin.h index 1db1177..0d1bd68d 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin.h +++ b/third_party/blink/renderer/platform/weborigin/security_origin.h
@@ -323,6 +323,16 @@ // if we need it for something more general. static String CanonicalizeHost(const String& host, bool* success); + // Return a security origin that is assigned to the agent cluster. This will + // be a copy of this security origin if the current agent doesn't match the + // provided agent, otherwise it will be a reference to this. + scoped_refptr<SecurityOrigin> GetOriginForAgentCluster( + const base::UnguessableToken& cluster_id); + + const base::UnguessableToken& AgentClusterId() const { + return agent_cluster_id_; + } + private: constexpr static const uint16_t kInvalidPort = 0; @@ -342,8 +352,13 @@ // Create a tuple SecurityOrigin, with parameters via KURL explicit SecurityOrigin(const KURL& url); + enum class ConstructIsolatedCopy { kConstructIsolatedCopyBit }; // Clone a SecurityOrigin which is safe to use on other threads. - explicit SecurityOrigin(const SecurityOrigin* other); + SecurityOrigin(const SecurityOrigin* other, ConstructIsolatedCopy); + + enum class ConstructSameThreadCopy { kConstructSameThreadCopyBit }; + // Clone a SecurityOrigin which is *NOT* safe to use on other threads. + SecurityOrigin(const SecurityOrigin* other, ConstructSameThreadCopy); // FIXME: Rename this function to something more semantic. bool PassesFileCheck(const SecurityOrigin*) const; @@ -368,6 +383,10 @@ bool is_opaque_origin_potentially_trustworthy_ = false; bool cross_agent_cluster_access_ = false; + // A security origin can have an empty |agent_cluster_id_|. It occurs in the + // cases where a security origin hasn't been assigned to a document yet. + base::UnguessableToken agent_cluster_id_; + // For opaque origins, tracks the non-opaque origin from which the opaque // origin is derived. const scoped_refptr<const SecurityOrigin> precursor_origin_;
diff --git a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc index 1acaaf1..b5bd179c 100644 --- a/third_party/blink/renderer/platform/weborigin/security_origin_test.cc +++ b/third_party/blink/renderer/platform/weborigin/security_origin_test.cc
@@ -42,6 +42,7 @@ #include "third_party/blink/renderer/platform/weborigin/security_origin_hash.h" #include "third_party/blink/renderer/platform/weborigin/security_policy.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" +#include "third_party/blink/renderer/platform/wtf/text/string_operators.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "url/gurl.h" #include "url/url_util.h" @@ -816,6 +817,7 @@ } TEST_F(SecurityOriginTest, ToTokenForFastCheck) { + base::UnguessableToken agent_cluster_id = base::UnguessableToken::Create(); constexpr struct { const char* url; const char* token; @@ -839,9 +841,13 @@ for (const auto& test : kTestCases) { SCOPED_TRACE(test.url); - scoped_refptr<const SecurityOrigin> origin = - SecurityOrigin::CreateFromString(test.url); - EXPECT_EQ(test.token, origin->ToTokenForFastCheck()) << test.token; + scoped_refptr<SecurityOrigin> origin = + SecurityOrigin::CreateFromString(test.url)->GetOriginForAgentCluster( + agent_cluster_id); + String expected_token; + if (test.token) + expected_token = test.token + String(agent_cluster_id.ToString().c_str()); + EXPECT_EQ(expected_token, origin->ToTokenForFastCheck()) << expected_token; } }
diff --git a/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h b/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h index 929468d..ee7c89a 100644 --- a/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h +++ b/third_party/blink/renderer/platform/wtf/typed_arrays/array_buffer_contents.h
@@ -32,6 +32,7 @@ #include "base/memory/scoped_refptr.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/assertions.h" +#include "third_party/blink/renderer/platform/wtf/cross_thread_copier.h" #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/blink/renderer/platform/wtf/wtf.h" #include "third_party/blink/renderer/platform/wtf/wtf_export.h" @@ -56,6 +57,8 @@ DISALLOW_COPY_AND_ASSIGN(DataHandle); public: + DataHandle() : DataHandle(nullptr, 0, nullptr, nullptr) {} + DataHandle(void* data, size_t length, DataDeleter deleter, @@ -82,6 +85,8 @@ return *this; } + void reset() { *this = DataHandle(); } + void* Data() const { return data_; } size_t DataLength() const { return data_length_; } @@ -226,6 +231,15 @@ DISALLOW_COPY_AND_ASSIGN(ArrayBufferContents); }; +template <> +struct CrossThreadCopier<ArrayBufferContents::DataHandle> { + STATIC_ONLY(CrossThreadCopier); + using Type = ArrayBufferContents::DataHandle; + static Type Copy(Type handle) { + return handle; // This is in fact a move. + } +}; + } // namespace WTF #endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_WTF_TYPED_ARRAYS_ARRAY_BUFFER_CONTENTS_H_
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 2359ef6..668639c 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -6374,9 +6374,6 @@ # Sheriff 2019-07-26 crbug.com/835943 [ Debug ] http/tests/appcache/non-html.xhtml [ Crash Pass ] crbug.com/874866 [ Linux Debug ] media/controls/doubletap-to-jump-backwards.html [ Failure ] -crbug.com/987915 virtual/scalefactor200withoutzoom/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html [ Pass Failure ] -crbug.com/987915 virtual/scalefactor200/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html [ Pass Failure ] -crbug.com/987915 external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html [ Pass Failure ] crbug.com/988231 external/wpt/event-timing/observethenonload.html [ Pass Timeout ] crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-alt-f8-twice.html [ Pass Failure ] crbug.com/988232 virtual/controls-refresh/fast/forms/controls-new-ui/password/password-alt-f8.html [ Pass Failure ] @@ -6456,9 +6453,13 @@ crbug.com/856601 [ Linux ] external/wpt/generic-sensor/idlharness.https.window.html [ Pass Timeout ] crbug.com/856601 [ Linux ] external/wpt/secure-contexts/idlharness.any.html [ Pass Timeout ] +# Sheriff 2019-08-14 +crbug.com/993671 [ Win ] virtual/audio-service/http/tests/media/video-frame-size-change.html [ Pass Failure ] + #Sheriff 2019-08-12 crbug.com/783154 [ Linux Debug ] virtual/audio-service/media/controls/doubletap-to-jump-backwards.html [ Failure ] crbug.com/993238 fast/frames/frame-name-reset.html [ Pass Failure ] # Sheriff 2019-08-14 crbug.com/993328 [ Mac ] virtual/audio-service/media/video-currentTime.html [ Pass Failure ] +crbug.com/993669 [ Mac ] virtual/audio-service/media/video-zoom.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json index 81c2bcb..145e3e35 100644 --- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json +++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -162119,21 +162119,66 @@ "import-maps/builtin-import-scheme.tentative-expected.txt": [ [] ], - "import-maps/resolving.tentative-expected.txt": [ + "import-maps/imported/parsing-addresses.tentative-expected.txt": [ + [] + ], + "import-maps/imported/parsing-schema.tentative-expected.txt": [ + [] + ], + "import-maps/imported/parsing-scope-keys.tentative-expected.txt": [ + [] + ], + "import-maps/imported/parsing-specifier-keys.tentative-expected.txt": [ + [] + ], + "import-maps/imported/resolving-builtins.tentative-expected.txt": [ + [] + ], + "import-maps/imported/resolving-scopes.tentative-expected.txt": [ + [] + ], + "import-maps/imported/resolving.tentative-expected.txt": [ + [] + ], + "import-maps/imported/resources/helpers/parsing.js": [ + [] + ], + "import-maps/imported/resources/parsing-addresses.js": [ + [] + ], + "import-maps/imported/resources/parsing-schema.js": [ + [] + ], + "import-maps/imported/resources/parsing-scope-keys.js": [ + [] + ], + "import-maps/imported/resources/parsing-specifier-keys.js": [ + [] + ], + "import-maps/imported/resources/resolving-builtins.js": [ + [] + ], + "import-maps/imported/resources/resolving-not-yet-implemented.js": [ + [] + ], + "import-maps/imported/resources/resolving-scopes.js": [ + [] + ], + "import-maps/imported/resources/resolving.js": [ [] ], "import-maps/resources/empty.js": [ [] ], + "import-maps/resources/jest-test-helper.js": [ + [] + ], "import-maps/resources/log.js": [ [] ], "import-maps/resources/log.js.headers": [ [] ], - "import-maps/resources/resolving.js": [ - [] - ], "import-maps/resources/test-helper.js": [ [] ], @@ -178496,9 +178541,6 @@ "xhr/folder.txt": [ [] ], - "xhr/getallresponseheaders-expected.txt": [ - [] - ], "xhr/idlharness.any.sharedworker-expected.txt": [ [] ], @@ -207259,6 +207301,24 @@ {} ] ], + "css/css-rhythm/parsing/line-height-step-computed.html": [ + [ + "css/css-rhythm/parsing/line-height-step-computed.html", + {} + ] + ], + "css/css-rhythm/parsing/line-height-step-invalid.html": [ + [ + "css/css-rhythm/parsing/line-height-step-invalid.html", + {} + ] + ], + "css/css-rhythm/parsing/line-height-step-valid.html": [ + [ + "css/css-rhythm/parsing/line-height-step-valid.html", + {} + ] + ], "css/css-scoping/host-descendant-invalidation.html": [ [ "css/css-scoping/host-descendant-invalidation.html", @@ -209665,6 +209725,24 @@ {} ] ], + "css/css-text-decor/parsing/text-shadow-computed.html": [ + [ + "css/css-text-decor/parsing/text-shadow-computed.html", + {} + ] + ], + "css/css-text-decor/parsing/text-shadow-invalid.html": [ + [ + "css/css-text-decor/parsing/text-shadow-invalid.html", + {} + ] + ], + "css/css-text-decor/parsing/text-shadow-valid.html": [ + [ + "css/css-text-decor/parsing/text-shadow-valid.html", + {} + ] + ], "css/css-text-decor/parsing/text-underline-position-computed.html": [ [ "css/css-text-decor/parsing/text-underline-position-computed.html", @@ -250081,15 +250159,57 @@ {} ] ], - "import-maps/module-map-key.tentative.html": [ + "import-maps/imported/parsing-addresses.tentative.html": [ [ - "import-maps/module-map-key.tentative.html", + "import-maps/imported/parsing-addresses.tentative.html", {} ] ], - "import-maps/resolving.tentative.html": [ + "import-maps/imported/parsing-schema.tentative.html": [ [ - "import-maps/resolving.tentative.html", + "import-maps/imported/parsing-schema.tentative.html", + {} + ] + ], + "import-maps/imported/parsing-scope-keys.tentative.html": [ + [ + "import-maps/imported/parsing-scope-keys.tentative.html", + {} + ] + ], + "import-maps/imported/parsing-specifier-keys.tentative.html": [ + [ + "import-maps/imported/parsing-specifier-keys.tentative.html", + {} + ] + ], + "import-maps/imported/resolving-builtins.tentative.html": [ + [ + "import-maps/imported/resolving-builtins.tentative.html", + {} + ] + ], + "import-maps/imported/resolving-not-yet-implemented.tentative.html": [ + [ + "import-maps/imported/resolving-not-yet-implemented.tentative.html", + {} + ] + ], + "import-maps/imported/resolving-scopes.tentative.html": [ + [ + "import-maps/imported/resolving-scopes.tentative.html", + {} + ] + ], + "import-maps/imported/resolving.tentative.html": [ + [ + "import-maps/imported/resolving.tentative.html", + {} + ] + ], + "import-maps/module-map-key.tentative.html": [ + [ + "import-maps/module-map-key.tentative.html", {} ] ], @@ -373600,6 +373720,18 @@ "44123ac65d884c5dd69271c22e69bb4b694586ce", "reftest" ], + "css/css-rhythm/parsing/line-height-step-computed.html": [ + "4153645dddf9c07bde36490c82537b01f62874fa", + "testharness" + ], + "css/css-rhythm/parsing/line-height-step-invalid.html": [ + "e2049057f1e6da2910c789fcd325fb1bbe19282e", + "testharness" + ], + "css/css-rhythm/parsing/line-height-step-valid.html": [ + "ea47a63678620ffa7f7f376f9652d62803290577", + "testharness" + ], "css/css-rhythm/reference/line-height-step-basic-001.html": [ "343026e07b817cc0f7d225b461d98ccceb310df0", "support" @@ -377505,7 +377637,7 @@ "support" ], "css/css-text-decor/inheritance.html": [ - "b106343742e03aa305a3017610272c8692b2a428", + "9ee65b4e5926f043b4841bc1f5a7cf84e214ce49", "testharness" ], "css/css-text-decor/line-through-vertical.html": [ @@ -377580,6 +377712,18 @@ "1c1aef3ff00a9f0d3867be9d395485d5b93bbede", "testharness" ], + "css/css-text-decor/parsing/text-shadow-computed.html": [ + "a90738d825f2132bd6236f550f7525157b18e102", + "testharness" + ], + "css/css-text-decor/parsing/text-shadow-invalid.html": [ + "dfaa4a5b48b9e6b6c668bc1833083b1b2f453ced", + "testharness" + ], + "css/css-text-decor/parsing/text-shadow-valid.html": [ + "cbf9df547906aaa5095359ad3847123d3756205e", + "testharness" + ], "css/css-text-decor/parsing/text-underline-position-computed.html": [ "9019a58fa4830ae5541b3882bf42f385504d0bd4", "testharness" @@ -444240,22 +444384,114 @@ "bd24f3535507334a69bb98b711106466c8a340a3", "testharness" ], + "import-maps/imported/parsing-addresses.tentative-expected.txt": [ + "2cb305cf7bde562fa53cfe9fe913235740994b5d", + "support" + ], + "import-maps/imported/parsing-addresses.tentative.html": [ + "ddb3b724bb64e2edd60a620dc6ae1cc98f32a92a", + "testharness" + ], + "import-maps/imported/parsing-schema.tentative-expected.txt": [ + "35fd1694d6498f4bdc66e644f9b12d2067302c1c", + "support" + ], + "import-maps/imported/parsing-schema.tentative.html": [ + "6b7c0e5b0eb40eee9c8a415af5b1af87a4af3492", + "testharness" + ], + "import-maps/imported/parsing-scope-keys.tentative-expected.txt": [ + "22d627b0ea5ad2725452103b03f44791b79965aa", + "support" + ], + "import-maps/imported/parsing-scope-keys.tentative.html": [ + "601ac37720d700d3f68e3b2f6aeae3b06c112132", + "testharness" + ], + "import-maps/imported/parsing-specifier-keys.tentative-expected.txt": [ + "48c0791a885fc924ce233496b387a29fd63990c4", + "support" + ], + "import-maps/imported/parsing-specifier-keys.tentative.html": [ + "dd547f01d1dfb2379f6afa893385fadc8f1217d1", + "testharness" + ], + "import-maps/imported/resolving-builtins.tentative-expected.txt": [ + "031faeb63a4902f3be78fee2f3b26c90cae75d2b", + "support" + ], + "import-maps/imported/resolving-builtins.tentative.html": [ + "c1395c175c77455361e5ea51819ece56dd24737a", + "testharness" + ], + "import-maps/imported/resolving-not-yet-implemented.tentative.html": [ + "7db5f29f892976720a145499d6e40ccb8959b006", + "testharness" + ], + "import-maps/imported/resolving-scopes.tentative-expected.txt": [ + "9e08fefaefaaf23751642451971cd2f7e47ef4a3", + "support" + ], + "import-maps/imported/resolving-scopes.tentative.html": [ + "4985249f4e2951965ad78321208ee08eca8617fa", + "testharness" + ], + "import-maps/imported/resolving.tentative-expected.txt": [ + "39ebb09e8e672104425c908275bde416803a0c65", + "support" + ], + "import-maps/imported/resolving.tentative.html": [ + "339026259b0f0b8286bc68ddf6976dac0009418b", + "testharness" + ], + "import-maps/imported/resources/helpers/parsing.js": [ + "5c22f6de710ea32753707273be5d63a285633860", + "support" + ], + "import-maps/imported/resources/parsing-addresses.js": [ + "0f5fc73506b1222dd7b3ac422d8c6232ac202bd7", + "support" + ], + "import-maps/imported/resources/parsing-schema.js": [ + "695034533c7faa248a29436cfbe805f86506dc48", + "support" + ], + "import-maps/imported/resources/parsing-scope-keys.js": [ + "cd1d9b34890971dbb21f7bde5d34ed9f2cc91f20", + "support" + ], + "import-maps/imported/resources/parsing-specifier-keys.js": [ + "9eb423a19eb1fb417526946c1701c7c9dde27c9c", + "support" + ], + "import-maps/imported/resources/resolving-builtins.js": [ + "a9383df843d44794351d5c6ffa5580d4d1254b9c", + "support" + ], + "import-maps/imported/resources/resolving-not-yet-implemented.js": [ + "93d782fdad83d58160061a4caa40659292a50866", + "support" + ], + "import-maps/imported/resources/resolving-scopes.js": [ + "ca19a66840601efe66fa2db24cffdcc0727681c5", + "support" + ], + "import-maps/imported/resources/resolving.js": [ + "29ee31ccbc936787894a43de1f6625608d14a192", + "support" + ], "import-maps/module-map-key.tentative.html": [ "13bd122c673144f001048eacbaf4fc7bb78c9b58", "testharness" ], - "import-maps/resolving.tentative-expected.txt": [ - "b5da00638a0048517bd8af6c5909be4e906ec4e2", - "support" - ], - "import-maps/resolving.tentative.html": [ - "f2b09a7ae02422c8f6fd3f8dad1f9b8d52a43831", - "testharness" - ], "import-maps/resources/empty.js": [ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", "support" ], + "import-maps/resources/jest-test-helper.js": [ + "86556ed3dd9585c95d258cbfabc8bb81ed5bc90d", + "support" + ], "import-maps/resources/log.js": [ "a024a29bf2482c78cf7eb96544d38217f1d81f81", "support" @@ -444264,10 +444500,6 @@ "cb762eff806849df46dc758ef7b98b63f27f54c9", "support" ], - "import-maps/resources/resolving.js": [ - "0409962e4d7904bd9ddbe8601b7328d8d0ad6d11", - "support" - ], "import-maps/resources/test-helper.js": [ "2447bfb94353e1ec193857cbcda79f46556216a1", "support" @@ -445977,7 +446209,7 @@ "testharness" ], "lint.whitelist": [ - "c344c3a834444db4be24db1d0132c85a4b14395c", + "ea899da8b3c7a8197db04fd8ed4f47f6c19940fb", "support" ], "loading/lazyload/common.js": [ @@ -470261,11 +470493,11 @@ "support" ], "resources/webidl2/lib/README.md": [ - "3f9d75f57ba8506537f75ae2958df6a74abcba3d", + "1bd583269d2929a16b1c7ad0c58fab6e99b72a10", "support" ], "resources/webidl2/lib/webidl2.js": [ - "9cb975a8bb30075e7ab377bc95b69ecc4f7e77f6", + "900694b095df7f6a4b791ea41e096744d06a6089", "support" ], "resources/webidl2/lib/webidl2.js.headers": [ @@ -485977,7 +486209,7 @@ "testharness" ], "web-animations/animation-model/animation-types/property-list.js": [ - "7b14797d962d5a52e641a1823e2b88927eabba90", + "3c1750f1f266985a449ab19e212a1166369f230d", "support" ], "web-animations/animation-model/animation-types/property-types.js": [ @@ -497700,10 +497932,6 @@ "2cd8098185963658171889ecfe226b44c02bbb9d", "testharness" ], - "xhr/getallresponseheaders-expected.txt": [ - "69617d196a6c6c8843d6dd55ec5bb6137a39d8b0", - "support" - ], "xhr/getallresponseheaders-status.htm": [ "a02ab457452262eb8c846904ad65c84671486d5d", "testharness"
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-001.html b/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-001.html index 881bb18..7ce3b69 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-001.html +++ b/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-001.html
@@ -29,7 +29,7 @@ test( function(){ var target = document.getElementById("target"); - assert_equals(getComputedStyle(target).gap, "50px 50px"); + assert_equals(getComputedStyle(target).gap, "50px"); assert_equals(getComputedStyle(target).rowGap, "50px"); assert_equals(getComputedStyle(target).columnGap, "50px"); }, "gap is interpolable");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-002.html b/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-002.html index 44d8c70b..6056aad 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-002.html +++ b/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-002.html
@@ -28,7 +28,7 @@ test( function(){ var target = document.getElementById("target"); - assert_equals(getComputedStyle(target).gap, "100px 100px"); + assert_equals(getComputedStyle(target).gap, "100px"); assert_equals(getComputedStyle(target).rowGap, "100px"); assert_equals(getComputedStyle(target).columnGap, "100px"); }, "gap: normal is not interpolable");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-003.html b/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-003.html index c047946f..2ec4551a 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-003.html +++ b/third_party/blink/web_tests/external/wpt/css/css-align/gaps/gap-animation-003.html
@@ -27,7 +27,7 @@ test( function(){ var target = document.getElementById("target"); - assert_equals(getComputedStyle(target).gap, "100px 100px"); + assert_equals(getComputedStyle(target).gap, "100px"); assert_equals(getComputedStyle(target).rowGap, "100px"); assert_equals(getComputedStyle(target).columnGap, "100px"); }, "Default gap is not interpolable");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-computed.html b/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-computed.html new file mode 100644 index 0000000..b93b237 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-computed.html
@@ -0,0 +1,35 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Box Alignment Level 3: getComputedStyle().gap</title> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-gap"> +<meta name="assert" content="gap computed value is a pair of keyword or <length-percentage> values."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<style> + #target { + font-size: 40px; + } +</style> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("gap", "normal"); +test_computed_value("gap", "10px"); +test_computed_value("gap", "20%"); +test_computed_value("gap", "calc(20% + 10px)"); +test_computed_value("gap", "calc(-0.5em + 10px)", "0px"); +test_computed_value("gap", "calc(0.5em + 10px)", "30px"); + +test_computed_value("gap", "normal 10px"); +test_computed_value("gap", "10px 20%"); +test_computed_value("gap", "20% calc(20% + 10px)"); +test_computed_value("gap", "calc(20% + 10px) normal"); + +test_computed_value("gap", "calc(-0.5em + 10px) calc(0.5em + 10px)", "0px 30px"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-invalid.html new file mode 100644 index 0000000..c2eae8f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-invalid.html
@@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Box Alignment Level 3: parsing gap with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-gap"> +<meta name="assert" content="gap supports only the grammar '<row-gap> <column-gap>?'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("gap", "auto"); +test_invalid_value("gap", "-10px"); + +test_invalid_value("gap", "10px 20% 30px"); +test_invalid_value("gap", "normal 10px normal"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-valid.html b/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-valid.html new file mode 100644 index 0000000..3104e3fb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-align/parsing/gap-valid.html
@@ -0,0 +1,26 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Box Alignment Level 3: parsing gap with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-align-3/#propdef-gap"> +<meta name="assert" content="row-gap supports the full grammar '<row-gap> <column-gap>?'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("gap", "normal normal", "normal"); +test_valid_value("gap", "10px 10px", "10px"); +test_valid_value("gap", "20% 20%", "20%"); +test_valid_value("gap", "calc(20% + 10px) calc(20% + 10px)", "calc(20% + 10px)"); + +test_valid_value("gap", "normal 10px"); +test_valid_value("gap", "10px 20%"); +test_valid_value("gap", "20% calc(20% + 10px)"); +test_valid_value("gap", "calc(20% + 10px) 0px"); +test_valid_value("gap", "0px normal"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-computed.html b/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-computed.html new file mode 100644 index 0000000..4153645 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-computed.html
@@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Rhythmic Sizing: getComputedStyle().lineHeightStep</title> +<link rel="help" href="https://drafts.csswg.org/css-rhythm/#propdef-line-height-step"> +<meta name="assert" content="line-height-step computed value is an absolute length."> +<meta name="assert" content="line-height-step is not negative."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<style> + #target { + font-size: 40px; + } +</style> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("line-height-step", "calc(10px + 0.5em)", "30px"); +test_computed_value("line-height-step", "calc(10px - 0.5em)", "0px"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-invalid.html new file mode 100644 index 0000000..e204905 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-invalid.html
@@ -0,0 +1,24 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Rhythmic Sizing: parsing line-height-step with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-rhythm/#propdef-line-height-step"> +<meta name="assert" content="line-height-step supports only the grammar '<length>'."> +<meta name="assert" content="line-height-step rejects negative lengths."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_invalid_value("line-height-step", "auto"); +test_invalid_value("line-height-step", "normal"); + +test_invalid_value("line-height-step", "10"); +test_invalid_value("line-height-step", "10px 20px"); +test_invalid_value("line-height-step", "-1px"); +test_invalid_value("line-height-step", "4%"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-valid.html b/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-valid.html new file mode 100644 index 0000000..ea47a636 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-rhythm/parsing/line-height-step-valid.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Rhythmic Sizing: parsing line-height-step with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-rhythm/#propdef-line-height-step"> +<meta name="assert" content="line-height-step supports the full grammar '<length>'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +</head> +<body> +<script> +test_valid_value("line-height-step", "0", "0px"); +test_valid_value("line-height-step", "1px"); +test_valid_value("line-height-step", "calc(2em + 3ex)"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html index b1063437..9ee65b4e 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html
@@ -26,7 +26,7 @@ assert_not_inherited('text-decoration-style', 'solid', 'dashed'); assert_inherited('text-emphasis-color', 'rgba(2, 3, 4, 0.5)', 'rgba(42, 53, 64, 0.75)'); assert_inherited('text-emphasis-position', 'over right', 'under left'); -assert_inherited('text-emphasis-style', 'none', 'filled triangle'); +assert_inherited('text-emphasis-style', 'none', 'triangle'); assert_inherited('text-shadow', 'none', 'rgba(42, 53, 64, 0.75) 10px 20px 0px'); assert_inherited('text-underline-position', 'auto', 'under');
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-computed.html new file mode 100644 index 0000000..a90738d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-computed.html
@@ -0,0 +1,31 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: getComputedStyle().textShadow</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property"> +<meta name="assert" content="text-shadow computed value is none or a list, each item a color and lengths."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +<style> + #target { + font-size: 40px; + color: blue; + } +</style> +<div id="target"></div> +<script> +'use strict'; +const red = 'rgb(255, 0, 0)'; +const lime = 'rgb(0, 255, 0)'; +const currentColor = 'rgb(0, 0, 255)'; + +test_computed_value("text-shadow", "none"); + +test_computed_value("text-shadow", "10px 20px", currentColor + " 10px 20px 0px"); +test_computed_value("text-shadow", "red 10px 20px 30px", red + " 10px 20px 30px"); +test_computed_value("text-shadow", "calc(0.5em + 10px) calc(0.5em + 10px) calc(0.5em + 10px)", currentColor + " 30px 30px 30px"); +test_computed_value("text-shadow", "calc(-0.5em + 10px) calc(-0.5em + 10px) calc(-0.5em + 10px)", currentColor + " -10px -10px 0px"); + +test_computed_value("text-shadow", "10px 20px, 30px 40px", currentColor + " 10px 20px 0px, " + currentColor + " 30px 40px 0px"); +test_computed_value("text-shadow", "lime 10px 20px 30px, red 40px 50px", lime + " 10px 20px 30px, " + red + " 40px 50px 0px"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-invalid.html new file mode 100644 index 0000000..dfaa4a5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-invalid.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-shadow with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property"> +<meta name="assert" content="text-shadow supports only the grammar 'none | [ <color>? && <length>{2,3} ]#'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_invalid_value("text-shadow", "auto"); + +test_invalid_value("text-shadow", "10px 20px -30px"); + +test_invalid_value("text-shadow", "10px"); +test_invalid_value("text-shadow", "10px 20px 30px 40px"); +test_invalid_value("text-shadow", "red 10px 20px blue"); +test_invalid_value("text-shadow", "10% 20px"); +test_invalid_value("text-shadow", "10px 20% 30px"); +test_invalid_value("text-shadow", "lime 10px 20px 30%"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-valid.html new file mode 100644 index 0000000..cbf9df5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-shadow-valid.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-shadow with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-shadow-property"> +<meta name="assert" content="text-shadow supports the full grammar 'none | [ <color>? && <length>{2,3} ]#'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_valid_value("text-shadow", "none"); + +test_valid_value("text-shadow", "10px 20px"); +test_valid_value("text-shadow", "10px 20px 30px"); +test_valid_value("text-shadow", "calc(1em + 2px) calc(3em + 4px) calc(5em + 6px)"); +test_valid_value("text-shadow", "-10px 20px 30px"); +test_valid_value("text-shadow", "10px -20px 30px"); +test_valid_value("text-shadow", "rgb(255, 0, 0) 10px 20px"); +test_valid_value("text-shadow", "10px 20px 30px lime", "lime 10px 20px 30px"); + +test_valid_value("text-shadow", "10px 20px, 30px 40px"); +test_valid_value("text-shadow", "lime 10px 20px 30px, blue 40px 50px"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/composited-transform.html b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/composited-transform.html new file mode 100644 index 0000000..182321b9 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-transforms/animation/composited-transform.html
@@ -0,0 +1,38 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>Composition of transform animations</title> +<link rel="help" href="https://drafts.csswg.org/css-transforms-2/#combining-transform-lists"> +<meta name="assert" content="transform animations should composite correctly"> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> + +<div id="target"><div> + +<script> +test(() => { + var anim1 = target.animate( + { transform: [ 'translateX(0)', 'translateX(100px)' ]}, + 1000 + ); + var anim2 = target.animate( + { transform: [ 'translateY(0)', 'translateY(100px)' ]}, + {duration: 1000, composite: 'add'} + ); + + anim1.pause(); + anim2.pause(); + + anim1.currentTime = 200; + anim2.currentTime = 800; + + // The computation here should be: + // underlying_value = 'translateX(0)' --> 'translateX(100px)' @ 0.2 + // = 'translateX(20px)' + // final_value = 0.2 * ('translateX(20px) translateY(0)') + + // 0.8 * ('translateX(20px) translateY(100px)') + // = 'translateX(20px) translateY(80px)' + // = 'matrix(1, 0, 0, 1, 20, 80)' + assert_equals(getComputedStyle(target).transform, 'matrix(1, 0, 0, 1, 20, 80)') +}, 'An additive transform animation on-top of a replace transform animation ' + + 'should composite correctly'); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-addresses.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-addresses.tentative-expected.txt new file mode 100644 index 0000000..2cb305c --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-addresses.tentative-expected.txt
@@ -0,0 +1,18 @@ +This is a testharness.js-based test. +PASS Relative URL-like addresses / should accept strings prefixed with ./, ../, or / +FAIL Relative URL-like addresses / should not accept strings prefixed with ./, ../, or / for data: base URLs assert_equals: expected "{\"dotDotSlash\":[],\"dotSlash\":[],\"slash\":[]}" but got "{\"dotDotSlash\":[\"http://web-platform.test:8001/import-maps/foo\"],\"dotSlash\":[\"http://web-platform.test:8001/import-maps/imported/foo\"],\"slash\":[\"http://web-platform.test:8001/foo\"]}" +PASS Relative URL-like addresses / should accept the literal strings ./, ../, or / with no suffix +PASS Relative URL-like addresses / should ignore percent-encoded variants of ./, ../, or / +PASS Built-in module addresses / should accept URLs using the built-in module scheme +PASS Built-in module addresses / should ignore percent-encoded variants of the built-in module scheme +FAIL Built-in module addresses / should allow built-in module URLs that contain "/" or "\" assert_equals: expected "{\"backslash\":[\"std:foo\\\baz\"],\"slashEnd\":[\"std:foo/\"],\"slashMiddle\":[\"std:foo/bar\"]}" but got "{\"backslash\":[\"std:foo\\baz\"],\"slashEnd\":[\"std:foo/\"],\"slashMiddle\":[\"std:foo/bar\"]}" +FAIL Absolute URL addresses / should only accept absolute URL addresses with fetch schemes assert_equals: expected "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[\"filesystem:good\"],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[],\"javascript\":[],\"mailto\":[],\"wss\":[]}" but got "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[\"import:bad\"],\"javascript\":[\"javascript:bad\"],\"mailto\":[\"mailto:bad\"],\"wss\":[\"wss://bad/\"]}" +FAIL Absolute URL addresses / should only accept absolute URL addresses with fetch schemes inside arrays assert_equals: expected "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[\"filesystem:good\"],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[],\"javascript\":[],\"mailto\":[],\"wss\":[]}" but got "{\"about\":[\"about:good\"],\"blob\":[\"blob:good\"],\"data\":[\"data:good\"],\"file\":[\"file:///good\"],\"filesystem\":[],\"ftp\":[\"ftp://good/\"],\"http\":[\"http://good/\"],\"https\":[\"https://good/\"],\"import\":[\"import:bad\"],\"javascript\":[\"javascript:bad\"],\"mailto\":[\"mailto:bad\"],\"wss\":[\"wss://bad/\"]}" +FAIL Absolute URL addresses / should parse absolute URLs, ignoring unparseable ones assert_equals: expected "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/%41\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[],\"unparseable2\":[],\"unparseable3\":[]}" but got "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/A\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[\"https://ex%20ample.org/\"],\"unparseable2\":[],\"unparseable3\":[]}" +FAIL Absolute URL addresses / should parse absolute URLs, ignoring unparseable ones inside arrays assert_equals: expected "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/%41\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[],\"unparseable2\":[],\"unparseable3\":[]}" but got "{\"invalidButParseable1\":[\"https://example.org/\"],\"invalidButParseable2\":[\"https://example.com///\"],\"noPercentDecoding\":[\"https://example.com/A\"],\"percentDecoding\":[\"https://example.com/\"],\"prettyNormal\":[\"https://example.net/\"],\"unparseable1\":[\"https://ex%20ample.org/\"],\"unparseable2\":[],\"unparseable3\":[]}" +FAIL Failing addresses: mismatched trailing slashes / should warn for the simple case assert_equals: expected "{\"std:trailer/\":[],\"trailer/\":[]}" but got "{\"trailer/\":[\"https://base.example/notrailer\"]}" +FAIL Failing addresses: mismatched trailing slashes / should warn for a mismatch alone in an array assert_equals: expected "{\"std:trailer/\":[],\"trailer/\":[]}" but got "{\"trailer/\":[\"https://base.example/notrailer\"]}" +FAIL Failing addresses: mismatched trailing slashes / should warn for a mismatch alongside non-mismatches in an array assert_equals: expected "{\"std:trailer/\":[\"https://base.example/bim-atrailer/\"],\"trailer/\":[\"https://base.example/atrailer/\"]}" but got "{\"trailer/\":[]}" +PASS Other invalid addresses / should ignore unprefixed strings that are not absolute URLs +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-addresses.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-addresses.tentative.html new file mode 100644 index 0000000..ddb3b724 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-addresses.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-addresses.js +--> +<script type="module" src="resources/parsing-addresses.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-schema.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-schema.tentative-expected.txt new file mode 100644 index 0000000..35fd169 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-schema.tentative-expected.txt
@@ -0,0 +1,16 @@ +This is a testharness.js-based test. +FAIL Invalid JSON assert_throws: function "() => parseFromString('{ imports: {} }', 'https://base.example/')" did not throw +FAIL Mismatching the top-level schema / should throw for top-level non-objects assert_throws: function "() => parseFromString(input, baseURL)" did not throw +FAIL Mismatching the top-level schema / should throw if imports is a non-object assert_throws: function "() => parseFromString(input, baseURL)" did not throw +FAIL Mismatching the top-level schema / should throw if scopes is a non-object assert_throws: function "() => parseFromString(input, baseURL)" did not throw +FAIL Mismatching the top-level schema / should ignore unspecified top-level entries assert_object_equals: expected property "0" missing +FAIL Mismatching the specifier map schema / should ignore entries where the address is not a string, array, or null assert_equals: expected "{\"bar\":[\"https://example.com/\"]}" but got "{\"bar\":[\"https://example.com/\"],\"foo\":[]}" +PASS Mismatching the specifier map schema / should ignore entries where the specifier key is an empty string +PASS Mismatching the specifier map schema / should ignore members of an address array that are not strings +FAIL Mismatching the specifier map schema / should throw if a scope's value is not an object assert_throws: function "() => parseFromString(input, baseURL)" did not throw +PASS Normalization / should normalize empty import maps to have imports and scopes keys +PASS Normalization / should normalize an import map without imports to have imports +PASS Normalization / should normalize an import map without scopes to have scopes +PASS Normalization / should normalize addresses to arrays +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-schema.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-schema.tentative.html new file mode 100644 index 0000000..6b7c0e5 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-schema.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-schema.js +--> +<script type="module" src="resources/parsing-schema.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-scope-keys.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-scope-keys.tentative-expected.txt new file mode 100644 index 0000000..22d627b --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-scope-keys.tentative-expected.txt
@@ -0,0 +1,12 @@ +This is a testharness.js-based test. +PASS Relative URL scope keys / should work with no prefix +PASS Relative URL scope keys / should work with ./, ../, and / prefixes +PASS Relative URL scope keys / should work with /s, ?s, and #s +PASS Relative URL scope keys / should work with an empty string scope key +PASS Relative URL scope keys / should work with / suffixes +PASS Relative URL scope keys / should deduplicate based on URL parsing rules +FAIL Absolute URL scope keys / should only accept absolute URL scope keys with fetch schemes assert_object_equals: expected property "0" missing +FAIL Absolute URL scope keys / should parse absolute URL scope keys, ignoring unparseable ones assert_object_equals: expected property "0" missing +FAIL Absolute URL scope keys / should ignore relative URL scope keys when the base URL is a data: URL assert_object_equals: expected property "0" missing +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-scope-keys.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-scope-keys.tentative.html new file mode 100644 index 0000000..601ac3772 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-scope-keys.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-scope-keys.js +--> +<script type="module" src="resources/parsing-scope-keys.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-specifier-keys.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-specifier-keys.tentative-expected.txt new file mode 100644 index 0000000..48c0791a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-specifier-keys.tentative-expected.txt
@@ -0,0 +1,10 @@ +This is a testharness.js-based test. +PASS Relative URL-like specifier keys / should absolutize strings prefixed with ./, ../, or / into the corresponding URLs +FAIL Relative URL-like specifier keys / should not absolutize strings prefixed with ./, ../, or / with a data: URL base assert_equals: expected "{\"../foo\":[\"https://example.com/dotdotslash\"],\"./foo\":[\"https://example.com/dotslash\"],\"/foo\":[\"https://example.com/slash\"]}" but got "{\"http://web-platform.test:8001/foo\":[\"https://example.com/slash\"],\"http://web-platform.test:8001/import-maps/foo\":[\"https://example.com/dotdotslash\"],\"http://web-platform.test:8001/import-maps/imported/foo\":[\"https://example.com/dotslash\"]}" +PASS Relative URL-like specifier keys / should absolutize the literal strings ./, ../, or / with no suffix +PASS Relative URL-like specifier keys / should treat percent-encoded variants of ./, ../, or / as bare specifiers +FAIL Absolute URL specifier keys / should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers assert_equals: expected "{\"about:good\":[\"https://base.example/about\"],\"blob:good\":[\"https://base.example/blob\"],\"data:good\":[\"https://base.example/data\"],\"file:///good\":[\"https://base.example/file\"],\"filesystem:good\":[\"https://base.example/filesystem\"],\"ftp://good/\":[\"https://base.example/ftp/\"],\"http://good/\":[\"https://base.example/http/\"],\"https://good/\":[\"https://base.example/https/\"],\"import:bad\":[\"https://base.example/import\"],\"javascript:bad\":[\"https://base.example/javascript\"],\"mailto:bad\":[\"https://base.example/mailto\"],\"wss:bad\":[\"https://base.example/wss\"]}" but got "{\"about:good\":[\"https://base.example/about\"],\"blob:good\":[\"https://base.example/blob\"],\"data:good\":[\"https://base.example/data\"],\"file:///good\":[\"https://base.example/file\"],\"filesystem:good\":[\"https://base.example/filesystem\"],\"ftp://good/\":[\"https://base.example/ftp/\"],\"http://good/\":[\"https://base.example/http/\"],\"https://good/\":[\"https://base.example/https/\"]}" +FAIL Absolute URL specifier keys / should parse absolute URLs, treating unparseable ones as bare specifiers assert_equals: expected "{\"http://[www.example.com]/\":[\"https://base.example/unparseable3/\"],\"https://ex ample.org/\":[\"https://base.example/unparseable1/\"],\"https://example.com/\":[\"https://base.example/percentDecoding/\"],\"https://example.com/%41\":[\"https://base.example/noPercentDecoding\"],\"https://example.com///\":[\"https://base.example/invalidButParseable2/\"],\"https://example.com:demo\":[\"https://base.example/unparseable2\"],\"https://example.net/\":[\"https://base.example/prettyNormal/\"],\"https://example.org/\":[\"https://base.example/invalidButParseable1/\"]}" but got "{\"http://[www.example.com]/\":[\"https://base.example/unparseable3/\"],\"https://ex%20ample.org/\":[\"https://base.example/unparseable1/\"],\"https://example.com/\":[\"https://base.example/percentDecoding/\"],\"https://example.com///\":[\"https://base.example/invalidButParseable2/\"],\"https://example.com/A\":[\"https://base.example/noPercentDecoding\"],\"https://example.com:demo\":[\"https://base.example/unparseable2\"],\"https://example.net/\":[\"https://base.example/prettyNormal/\"],\"https://example.org/\":[\"https://base.example/invalidButParseable1/\"]}" +FAIL Absolute URL specifier keys / should parse built-in module specifier keys, including with a "/" assert_equals: expected "{\"std:blank\":[\"https://base.example/blank\"],\"std:blank/\":[\"https://base.example/blank/\"],\"std:blank/foo\":[\"https://base.example/blank/foo\"],\"std:blank\\\foo\":[\"https://base.example/blank/backslashfoo\"]}" but got "{}" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-specifier-keys.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-specifier-keys.tentative.html new file mode 100644 index 0000000..dd547f01 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/parsing-specifier-keys.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/parsing-specifier-keys.js +--> +<script type="module" src="resources/parsing-specifier-keys.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-builtins.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-builtins.tentative-expected.txt new file mode 100644 index 0000000..031faeb --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-builtins.tentative-expected.txt
@@ -0,0 +1,16 @@ +This is a testharness.js-based test. +PASS Unmapped built-in module specifiers / should resolve "std:blank" to "std:blank" +FAIL Unmapped built-in module specifiers / should error resolving "std:none" assert_throws: function "() => resolveUnderTest(NONE)" did not throw +FAIL Remapping built-in module specifiers / should remap built-in modules assert_equals: expected "https://example.com/app/blank.mjs" but got "std:blank" +FAIL Remapping built-in module specifiers / should remap built-in modules with slashes assert_equals: expected "https://example.com/app/blank-slash/" but got "std:blank/" +FAIL Remapping built-in module specifiers / should remap built-in modules with fallbacks assert_equals: expected "https://example.com/app/none.mjs" but got "std:none" +FAIL Remapping built-in module specifiers / should remap built-in modules with slashes and fallbacks assert_equals: expected "https://example.com/app/blank/" but got "std:blank/" +PASS Remapping to built-in modules / should remap to "std:blank" +PASS Remapping to built-in modules / should fail when remapping to "std:blank/" +FAIL Remapping to built-in modules / should remap to "std:blank/for-testing" assert_equals: expected "std:blank/for-testing" but got "https://example.com/blank/for-testing" +PASS Remapping to built-in modules / should remap to "std:blank" for URL-like specifiers +PASS Remapping to built-in modules / should fail when remapping to "std:none" +FAIL Fallbacks with built-in module addresses / should resolve to "std:blank" Failed to resolve module specifier blank: Import Map: "blank" matches with "blank" but fails to be mapped (no viable URLs) +FAIL Fallbacks with built-in module addresses / should fall back past "std:none" Failed to resolve module specifier none: Import Map: "none" matches with "none" but fails to be mapped (no viable URLs) +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-builtins.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-builtins.tentative.html new file mode 100644 index 0000000..c1395c1 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-builtins.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-builtins.js +--> +<script type="module" src="resources/resolving-builtins.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-not-yet-implemented.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-not-yet-implemented.tentative.html new file mode 100644 index 0000000..7db5f29f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-not-yet-implemented.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-not-yet-implemented.js +--> +<script type="module" src="resources/resolving-not-yet-implemented.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-scopes.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-scopes.tentative-expected.txt new file mode 100644 index 0000000..9e08fefa --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-scopes.tentative-expected.txt
@@ -0,0 +1,17 @@ +This is a testharness.js-based test. +PASS Mapped using scope instead of "imports" / should fail when the mapping is to an empty array +FAIL Mapped using scope instead of "imports" / Exact vs. prefix based matching / should match correctly when both are in the map Failed to resolve module specifier moment: Relative references must start with either "/", "./", or "../". +FAIL Mapped using scope instead of "imports" / Exact vs. prefix based matching / should match correctly when only an exact match is in the map Failed to resolve module specifier moment: Relative references must start with either "/", "./", or "../". +FAIL Mapped using scope instead of "imports" / Exact vs. prefix based matching / should match correctly when only a prefix match is in the map Failed to resolve module specifier moment: Relative references must start with either "/", "./", or "../". +FAIL Mapped using scope instead of "imports" / Package-like scenarios / should resolve scoped assert_equals: expected "https://example.com/app/node_modules_2/lodash-es/lodash.js" but got "https://example.com/app/node_modules/lodash-es/lodash.js" +FAIL Mapped using scope instead of "imports" / Package-like scenarios / should apply best scope match assert_equals: expected "https://example.com/node_modules_3/moment/src/moment.js" but got "https://example.com/node_modules/moment/src/moment.js" +PASS Mapped using scope instead of "imports" / Package-like scenarios / should fallback to "imports" +PASS Mapped using scope instead of "imports" / Package-like scenarios / should still fail for package-like specifiers that are not declared +PASS Mapped using scope instead of "imports" / The scope inheritance example from the README / should fall back to "imports" when none match +FAIL Mapped using scope instead of "imports" / The scope inheritance example from the README / should use a direct scope override assert_equals: expected "https://example.com/a-2.mjs" but got "https://example.com/a-1.mjs" +FAIL Mapped using scope instead of "imports" / The scope inheritance example from the README / should use an indirect scope override assert_equals: expected "https://example.com/a-2.mjs" but got "https://example.com/a-1.mjs" +FAIL Mapped using scope instead of "imports" / Relative URL scope keys / should resolve an empty string scope using the import map URL assert_equals: expected "https://example.com/a-empty-string.mjs" but got "https://example.com/a-1.mjs" +FAIL Mapped using scope instead of "imports" / Relative URL scope keys / should resolve a ./ scope using the import map URL's directory assert_equals: expected "https://example.com/b-dot-slash.mjs" but got "https://example.com/b-1.mjs" +FAIL Mapped using scope instead of "imports" / Relative URL scope keys / should resolve a ../ scope using the import map URL's directory assert_equals: expected "https://example.com/c-dot-dot-slash.mjs" but got "https://example.com/c-1.mjs" +Harness: the test ran to completion. +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-scopes.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-scopes.tentative.html new file mode 100644 index 0000000..4985249f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving-scopes.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving-scopes.js +--> +<script type="module" src="resources/resolving-scopes.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative-expected.txt b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving.tentative-expected.txt similarity index 70% rename from third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative-expected.txt rename to third_party/blink/web_tests/external/wpt/import-maps/imported/resolving.tentative-expected.txt index b5da0063..39ebb09 100644 --- a/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative-expected.txt +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving.tentative-expected.txt
@@ -10,14 +10,17 @@ PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package submodules PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should work for package names that end in a slash by just passing through PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should still fail for package modules that are not declared +PASS Mapped using the "imports" key only (no scopes) / Package-like scenarios / should fail for package submodules that map to nowhere PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work for explicitly-mapped specifiers that happen to have a slash PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should work when the specifier has punctuation PASS Mapped using the "imports" key only (no scopes) / Tricky specifiers / should fail for attempting to get a submodule of something not declared with a trailing slash -PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap to built-in modules PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap to other URLs PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should fail for URLs that remap to empty arrays PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are just composed from / and . +FAIL Mapped using the "imports" key only (no scopes) / URL-like specifiers / should remap URLs that are prefix-matched by keys with trailing slashes assert_equals: expected "https://example.com/lib/url-trailing-slash/foo.mjs" but got "https://example.com/test/foo.mjs" PASS Mapped using the "imports" key only (no scopes) / URL-like specifiers / should use the last entry's address when URL-like specifiers parse to the same absolute URL -PASS Mapped using the "imports" key only (no scopes) / overlapping entries with trailing slashes / most-specific wins +PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key (no empty arrays) +PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key when empty arrays are involved for less-specific keys +PASS Mapped using the "imports" key only (no scopes) / Overlapping entries with trailing slashes / should favor the most-specific key when empty arrays are involved for more-specific keys Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving.tentative.html new file mode 100644 index 0000000..3390262 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resolving.tentative.html
@@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="../resources/jest-test-helper.js"></script> +<script type="module" src="resources/helpers/parsing.js"></script> + +<!-- +Imported from https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js +--> +<script type="module" src="resources/resolving.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/helpers/parsing.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/helpers/parsing.js new file mode 100644 index 0000000..5c22f6d --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/helpers/parsing.js
@@ -0,0 +1,50 @@ +'use strict'; +const { parseFromString } = require('../../lib/parser.js'); + +// Local modifications from upstream: +// Currently warnings and scopes are not checked in expectSpecifierMap(). +exports.expectSpecifierMap = (input, baseURL, output, warnings = []) => { + expect(parseFromString(`{ "imports": ${input} }`, baseURL)) + .toEqual({ imports: output, scopes: {} }); +}; + +exports.expectScopes = (inputArray, baseURL, outputArray, warnings = []) => { + const checkWarnings = testWarningHandler(warnings); + + const inputScopesAsStrings = inputArray.map(scopePrefix => `${JSON.stringify(scopePrefix)}: {}`); + const inputString = `{ "scopes": { ${inputScopesAsStrings.join(', ')} } }`; + + const outputScopesObject = {}; + for (const outputScopePrefix of outputArray) { + outputScopesObject[outputScopePrefix] = {}; + } + + expect(parseFromString(inputString, baseURL)).toEqual({ imports: {}, scopes: outputScopesObject }); + + checkWarnings(); +}; + +exports.expectBad = (input, baseURL, warnings = []) => { + const checkWarnings = testWarningHandler(warnings); + expect(() => parseFromString(input, baseURL)).toThrow(TypeError); + checkWarnings(); +}; + +exports.expectWarnings = (input, baseURL, output, warnings = []) => { + const checkWarnings = testWarningHandler(warnings); + expect(parseFromString(input, baseURL)).toEqual(output); + + checkWarnings(); +}; + +function testWarningHandler(expectedWarnings) { + const warnings = []; + const { warn } = console; + console.warn = warning => { + warnings.push(warning); + }; + return () => { + console.warn = warn; + expect(warnings).toEqual(expectedWarnings); + }; +}
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-addresses.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-addresses.js new file mode 100644 index 0000000..0f5fc73 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-addresses.js
@@ -0,0 +1,351 @@ +'use strict'; +const { expectSpecifierMap } = require('./helpers/parsing.js'); +const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); + +describe('Relative URL-like addresses', () => { + it('should accept strings prefixed with ./, ../, or /', () => { + expectSpecifierMap( + `{ + "dotSlash": "./foo", + "dotDotSlash": "../foo", + "slash": "/foo" + }`, + 'https://base.example/path1/path2/path3', + { + dotSlash: [expect.toMatchURL('https://base.example/path1/path2/foo')], + dotDotSlash: [expect.toMatchURL('https://base.example/path1/foo')], + slash: [expect.toMatchURL('https://base.example/foo')] + } + ); + }); + + it('should not accept strings prefixed with ./, ../, or / for data: base URLs', () => { + expectSpecifierMap( + `{ + "dotSlash": "./foo", + "dotDotSlash": "../foo", + "slash": "/foo" + }`, + 'data:text/html,test', + { + dotSlash: [], + dotDotSlash: [], + slash: [] + }, + [ + `Invalid address "./foo" for the specifier key "dotSlash".`, + `Invalid address "../foo" for the specifier key "dotDotSlash".`, + `Invalid address "/foo" for the specifier key "slash".` + ] + ); + }); + + it('should accept the literal strings ./, ../, or / with no suffix', () => { + expectSpecifierMap( + `{ + "dotSlash": "./", + "dotDotSlash": "../", + "slash": "/" + }`, + 'https://base.example/path1/path2/path3', + { + dotSlash: [expect.toMatchURL('https://base.example/path1/path2/')], + dotDotSlash: [expect.toMatchURL('https://base.example/path1/')], + slash: [expect.toMatchURL('https://base.example/')] + } + ); + }); + + it('should ignore percent-encoded variants of ./, ../, or /', () => { + expectSpecifierMap( + `{ + "dotSlash1": "%2E/", + "dotDotSlash1": "%2E%2E/", + "dotSlash2": ".%2F", + "dotDotSlash2": "..%2F", + "slash2": "%2F", + "dotSlash3": "%2E%2F", + "dotDotSlash3": "%2E%2E%2F" + }`, + 'https://base.example/path1/path2/path3', + { + dotSlash1: [], + dotDotSlash1: [], + dotSlash2: [], + dotDotSlash2: [], + slash2: [], + dotSlash3: [], + dotDotSlash3: [] + }, + [ + `Invalid address "%2E/" for the specifier key "dotSlash1".`, + `Invalid address "%2E%2E/" for the specifier key "dotDotSlash1".`, + `Invalid address ".%2F" for the specifier key "dotSlash2".`, + `Invalid address "..%2F" for the specifier key "dotDotSlash2".`, + `Invalid address "%2F" for the specifier key "slash2".`, + `Invalid address "%2E%2F" for the specifier key "dotSlash3".`, + `Invalid address "%2E%2E%2F" for the specifier key "dotDotSlash3".` + ] + ); + }); +}); + +describe('Built-in module addresses', () => { + it('should accept URLs using the built-in module scheme', () => { + expectSpecifierMap( + `{ + "foo": "${BUILT_IN_MODULE_SCHEME}:foo" + }`, + 'https://base.example/path1/path2/path3', + { + foo: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo`)] + } + ); + }); + + it('should ignore percent-encoded variants of the built-in module scheme', () => { + expectSpecifierMap( + `{ + "foo": "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" + }`, + 'https://base.example/path1/path2/path3', + { + foo: [] + }, + [`Invalid address "${encodeURIComponent(BUILT_IN_MODULE_SCHEME + ':')}foo" for the specifier key "foo".`] + ); + }); + + it('should allow built-in module URLs that contain "/" or "\\"', () => { + expectSpecifierMap( + `{ + "slashEnd": "${BUILT_IN_MODULE_SCHEME}:foo/", + "slashMiddle": "${BUILT_IN_MODULE_SCHEME}:foo/bar", + "backslash": "${BUILT_IN_MODULE_SCHEME}:foo\\\\baz" + }`, + 'https://base.example/path1/path2/path3', + { + slashEnd: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/`)], + slashMiddle: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo/bar`)], + backslash: [expect.toMatchURL(`${BUILT_IN_MODULE_SCHEME}:foo\\baz`)] + } + ); + }); +}); + +describe('Absolute URL addresses', () => { + it('should only accept absolute URL addresses with fetch schemes', () => { + expectSpecifierMap( + `{ + "about": "about:good", + "blob": "blob:good", + "data": "data:good", + "file": "file:///good", + "filesystem": "filesystem:good", + "http": "http://good/", + "https": "https://good/", + "ftp": "ftp://good/", + "import": "import:bad", + "mailto": "mailto:bad", + "javascript": "javascript:bad", + "wss": "wss:bad" + }`, + 'https://base.example/path1/path2/path3', + { + about: [expect.toMatchURL('about:good')], + blob: [expect.toMatchURL('blob:good')], + data: [expect.toMatchURL('data:good')], + file: [expect.toMatchURL('file:///good')], + filesystem: [expect.toMatchURL('filesystem:good')], + http: [expect.toMatchURL('http://good/')], + https: [expect.toMatchURL('https://good/')], + ftp: [expect.toMatchURL('ftp://good/')], + import: [], + mailto: [], + javascript: [], + wss: [] + }, + [ + `Invalid address "import:bad" for the specifier key "import".`, + `Invalid address "mailto:bad" for the specifier key "mailto".`, + `Invalid address "javascript:bad" for the specifier key "javascript".`, + `Invalid address "wss:bad" for the specifier key "wss".` + ] + ); + }); + + it('should only accept absolute URL addresses with fetch schemes inside arrays', () => { + expectSpecifierMap( + `{ + "about": ["about:good"], + "blob": ["blob:good"], + "data": ["data:good"], + "file": ["file:///good"], + "filesystem": ["filesystem:good"], + "http": ["http://good/"], + "https": ["https://good/"], + "ftp": ["ftp://good/"], + "import": ["import:bad"], + "mailto": ["mailto:bad"], + "javascript": ["javascript:bad"], + "wss": ["wss:bad"] + }`, + 'https://base.example/path1/path2/path3', + { + about: [expect.toMatchURL('about:good')], + blob: [expect.toMatchURL('blob:good')], + data: [expect.toMatchURL('data:good')], + file: [expect.toMatchURL('file:///good')], + filesystem: [expect.toMatchURL('filesystem:good')], + http: [expect.toMatchURL('http://good/')], + https: [expect.toMatchURL('https://good/')], + ftp: [expect.toMatchURL('ftp://good/')], + import: [], + mailto: [], + javascript: [], + wss: [] + }, + [ + `Invalid address "import:bad" for the specifier key "import".`, + `Invalid address "mailto:bad" for the specifier key "mailto".`, + `Invalid address "javascript:bad" for the specifier key "javascript".`, + `Invalid address "wss:bad" for the specifier key "wss".` + ] + ); + }); + + it('should parse absolute URLs, ignoring unparseable ones', () => { + expectSpecifierMap( + `{ + "unparseable1": "https://ex ample.org/", + "unparseable2": "https://example.com:demo", + "unparseable3": "http://[www.example.com]/", + "invalidButParseable1": "https:example.org", + "invalidButParseable2": "https://///example.com///", + "prettyNormal": "https://example.net", + "percentDecoding": "https://ex%41mple.com/", + "noPercentDecoding": "https://example.com/%41" + }`, + 'https://base.example/path1/path2/path3', + { + unparseable1: [], + unparseable2: [], + unparseable3: [], + invalidButParseable1: [expect.toMatchURL('https://example.org/')], + invalidButParseable2: [expect.toMatchURL('https://example.com///')], + prettyNormal: [expect.toMatchURL('https://example.net/')], + percentDecoding: [expect.toMatchURL('https://example.com/')], + noPercentDecoding: [expect.toMatchURL('https://example.com/%41')] + }, + [ + `Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`, + `Invalid address "https://example.com:demo" for the specifier key "unparseable2".`, + `Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".` + ] + ); + }); + + it('should parse absolute URLs, ignoring unparseable ones inside arrays', () => { + expectSpecifierMap( + `{ + "unparseable1": ["https://ex ample.org/"], + "unparseable2": ["https://example.com:demo"], + "unparseable3": ["http://[www.example.com]/"], + "invalidButParseable1": ["https:example.org"], + "invalidButParseable2": ["https://///example.com///"], + "prettyNormal": ["https://example.net"], + "percentDecoding": ["https://ex%41mple.com/"], + "noPercentDecoding": ["https://example.com/%41"] + }`, + 'https://base.example/path1/path2/path3', + { + unparseable1: [], + unparseable2: [], + unparseable3: [], + invalidButParseable1: [expect.toMatchURL('https://example.org/')], + invalidButParseable2: [expect.toMatchURL('https://example.com///')], + prettyNormal: [expect.toMatchURL('https://example.net/')], + percentDecoding: [expect.toMatchURL('https://example.com/')], + noPercentDecoding: [expect.toMatchURL('https://example.com/%41')] + }, + [ + `Invalid address "https://ex ample.org/" for the specifier key "unparseable1".`, + `Invalid address "https://example.com:demo" for the specifier key "unparseable2".`, + `Invalid address "http://[www.example.com]/" for the specifier key "unparseable3".` + ] + ); + }); +}); + +describe('Failing addresses: mismatched trailing slashes', () => { + it('should warn for the simple case', () => { + expectSpecifierMap( + `{ + "trailer/": "/notrailer", + "${BUILT_IN_MODULE_SCHEME}:trailer/": "/bim-notrailer" + }`, + 'https://base.example/path1/path2/path3', + { + 'trailer/': [], + [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [] + }, + [ + `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, + `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` + ] + ); + }); + + it('should warn for a mismatch alone in an array', () => { + expectSpecifierMap( + `{ + "trailer/": ["/notrailer"], + "${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-notrailer"] + }`, + 'https://base.example/path1/path2/path3', + { + 'trailer/': [], + [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [] + }, + [ + `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, + `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` + ] + ); + }); + + it('should warn for a mismatch alongside non-mismatches in an array', () => { + expectSpecifierMap( + `{ + "trailer/": ["/atrailer/", "/notrailer"], + "${BUILT_IN_MODULE_SCHEME}:trailer/": ["/bim-atrailer/", "/bim-notrailer"] + }`, + 'https://base.example/path1/path2/path3', + { + 'trailer/': [expect.toMatchURL('https://base.example/atrailer/')], + [`${BUILT_IN_MODULE_SCHEME}:trailer/`]: [expect.toMatchURL('https://base.example/bim-atrailer/')] + }, + [ + `Invalid address "https://base.example/notrailer" for package specifier key "trailer/". Package addresses must end with "/".`, + `Invalid address "https://base.example/bim-notrailer" for package specifier key "${BUILT_IN_MODULE_SCHEME}:trailer/". Package addresses must end with "/".` + ] + ); + }); +}); + +describe('Other invalid addresses', () => { + it('should ignore unprefixed strings that are not absolute URLs', () => { + for (const bad of ['bar', '\\bar', '~bar', '#bar', '?bar']) { + expectSpecifierMap( + `{ + "foo": ${JSON.stringify(bad)} + }`, + 'https://base.example/path1/path2/path3', + { + foo: [] + }, + [`Invalid address "${bad}" for the specifier key "foo".`] + ); + } + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-schema.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-schema.js new file mode 100644 index 0000000..69503453 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-schema.js
@@ -0,0 +1,139 @@ +'use strict'; +const { parseFromString } = require('../lib/parser.js'); +const { expectBad, expectWarnings, expectSpecifierMap } = require('./helpers/parsing.js'); + +const nonObjectStrings = ['null', 'true', '1', '"foo"', '[]']; + +test('Invalid JSON', () => { + expect(() => parseFromString('{ imports: {} }', 'https://base.example/')).toThrow(SyntaxError); +}); + +describe('Mismatching the top-level schema', () => { + it('should throw for top-level non-objects', () => { + for (const nonObject of nonObjectStrings) { + expectBad(nonObject, 'https://base.example/'); + } + }); + + it('should throw if imports is a non-object', () => { + for (const nonObject of nonObjectStrings) { + expectBad(`{ "imports": ${nonObject} }`, 'https://base.example/'); + } + }); + + it('should throw if scopes is a non-object', () => { + for (const nonObject of nonObjectStrings) { + expectBad(`{ "scopes": ${nonObject} }`, 'https://base.example/'); + } + }); + + it('should ignore unspecified top-level entries', () => { + expectWarnings( + `{ + "imports": {}, + "new-feature": {}, + "scops": {} + }`, + 'https://base.example/', + { imports: {}, scopes: {} }, + [ + `Invalid top-level key "new-feature". Only "imports" and "scopes" can be present.`, + `Invalid top-level key "scops". Only "imports" and "scopes" can be present.` + ] + ); + }); +}); + +describe('Mismatching the specifier map schema', () => { + const invalidAddressStrings = ['true', '1', '{}']; + const invalidInsideArrayStrings = ['null', 'true', '1', '{}', '[]']; + + it('should ignore entries where the address is not a string, array, or null', () => { + for (const invalid of invalidAddressStrings) { + expectSpecifierMap( + `{ + "foo": ${invalid}, + "bar": ["https://example.com/"] + }`, + 'https://base.example/', + { + bar: [expect.toMatchURL('https://example.com/')] + }, + [ + `Invalid address ${invalid} for the specifier key "foo". ` + + `Addresses must be strings, arrays, or null.` + ] + ); + } + }); + + it('should ignore entries where the specifier key is an empty string', () => { + expectSpecifierMap( + `{ + "": ["https://example.com/"] + }`, + 'https://base.example/', + {}, + [`Invalid empty string specifier key.`] + ); + }); + + it('should ignore members of an address array that are not strings', () => { + for (const invalid of invalidInsideArrayStrings) { + expectSpecifierMap( + `{ + "foo": ["https://example.com/", ${invalid}], + "bar": ["https://example.com/"] + }`, + 'https://base.example/', + { + foo: [expect.toMatchURL('https://example.com/')], + bar: [expect.toMatchURL('https://example.com/')] + }, + [ + `Invalid address ${invalid} inside the address array for the specifier key "foo". ` + + `Address arrays must only contain strings.` + ] + ); + } + }); + + it('should throw if a scope\'s value is not an object', () => { + for (const invalid of nonObjectStrings) { + expectBad(`{ "scopes": { "https://scope.example/": ${invalid} } }`, 'https://base.example/'); + } + }); +}); + +describe('Normalization', () => { + it('should normalize empty import maps to have imports and scopes keys', () => { + expect(parseFromString(`{}`, 'https://base.example/')) + .toEqual({ imports: {}, scopes: {} }); + }); + + it('should normalize an import map without imports to have imports', () => { + expect(parseFromString(`{ "scopes": {} }`, 'https://base.example/')) + .toEqual({ imports: {}, scopes: {} }); + }); + + it('should normalize an import map without scopes to have scopes', () => { + expect(parseFromString(`{ "imports": {} }`, 'https://base.example/')) + .toEqual({ imports: {}, scopes: {} }); + }); + + it('should normalize addresses to arrays', () => { + expectSpecifierMap( + `{ + "foo": "https://example.com/1", + "bar": ["https://example.com/2"], + "baz": null + }`, + 'https://base.example/', + { + foo: [expect.toMatchURL('https://example.com/1')], + bar: [expect.toMatchURL('https://example.com/2')], + baz: [] + } + ); + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-scope-keys.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-scope-keys.js new file mode 100644 index 0000000..cd1d9b3 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-scope-keys.js
@@ -0,0 +1,145 @@ +'use strict'; +const { expectScopes } = require('./helpers/parsing.js'); + +describe('Relative URL scope keys', () => { + it('should work with no prefix', () => { + expectScopes( + ['foo'], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/foo'] + ); + }); + + it('should work with ./, ../, and / prefixes', () => { + expectScopes( + ['./foo', '../foo', '/foo'], + 'https://base.example/path1/path2/path3', + [ + 'https://base.example/path1/path2/foo', + 'https://base.example/path1/foo', + 'https://base.example/foo' + ] + ); + }); + + it('should work with /s, ?s, and #s', () => { + expectScopes( + ['foo/bar?baz#qux'], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/foo/bar?baz#qux'] + ); + }); + + it('should work with an empty string scope key', () => { + expectScopes( + [''], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/path3'] + ); + }); + + it('should work with / suffixes', () => { + expectScopes( + ['foo/', './foo/', '../foo/', '/foo/', '/foo//'], + 'https://base.example/path1/path2/path3', + [ + 'https://base.example/path1/path2/foo/', + 'https://base.example/path1/path2/foo/', + 'https://base.example/path1/foo/', + 'https://base.example/foo/', + 'https://base.example/foo//' + ] + ); + }); + + it('should deduplicate based on URL parsing rules', () => { + expectScopes( + ['foo/\\', 'foo//', 'foo\\\\'], + 'https://base.example/path1/path2/path3', + ['https://base.example/path1/path2/foo//'] + ); + }); +}); + +describe('Absolute URL scope keys', () => { + it('should only accept absolute URL scope keys with fetch schemes', () => { + expectScopes( + [ + 'about:good', + 'blob:good', + 'data:good', + 'file:///good', + 'filesystem:good', + 'http://good/', + 'https://good/', + 'ftp://good/', + 'import:bad', + 'mailto:bad', + 'javascript:bad', + 'wss:ba' + ], + 'https://base.example/path1/path2/path3', + [ + 'about:good', + 'blob:good', + 'data:good', + 'file:///good', + 'filesystem:good', + 'http://good/', + 'https://good/', + 'ftp://good/' + ], + [ + 'Invalid scope "import:bad". Scope URLs must have a fetch scheme.', + 'Invalid scope "mailto:bad". Scope URLs must have a fetch scheme.', + 'Invalid scope "javascript:bad". Scope URLs must have a fetch scheme.', + 'Invalid scope "wss://ba/". Scope URLs must have a fetch scheme.' + ] + ); + }); + + it('should parse absolute URL scope keys, ignoring unparseable ones', () => { + expectScopes( + [ + 'https://ex ample.org/', + 'https://example.com:demo', + 'http://[www.example.com]/', + 'https:example.org', + 'https://///example.com///', + 'https://example.net', + 'https://ex%41mple.com/foo/', + 'https://example.com/%41' + ], + 'https://base.example/path1/path2/path3', + [ + 'https://base.example/path1/path2/example.org', // tricky case! remember we have a base URL + 'https://example.com///', + 'https://example.net/', + 'https://example.com/foo/', + 'https://example.com/%41' + ], + [ + 'Invalid scope "https://ex ample.org/" (parsed against base URL "https://base.example/path1/path2/path3").', + 'Invalid scope "https://example.com:demo" (parsed against base URL "https://base.example/path1/path2/path3").', + 'Invalid scope "http://[www.example.com]/" (parsed against base URL "https://base.example/path1/path2/path3").' + ] + ); + }); + + it('should ignore relative URL scope keys when the base URL is a data: URL', () => { + expectScopes( + [ + './foo', + '../foo', + '/foo' + ], + 'data:text/html,test', + [], + [ + 'Invalid scope "./foo" (parsed against base URL "data:text/html,test").', + 'Invalid scope "../foo" (parsed against base URL "data:text/html,test").', + 'Invalid scope "/foo" (parsed against base URL "data:text/html,test").' + ] + ); + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-specifier-keys.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-specifier-keys.js new file mode 100644 index 0000000..9eb423a --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/parsing-specifier-keys.js
@@ -0,0 +1,159 @@ +'use strict'; +const { expectSpecifierMap } = require('./helpers/parsing.js'); +const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); + +const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`; + +describe('Relative URL-like specifier keys', () => { + it('should absolutize strings prefixed with ./, ../, or / into the corresponding URLs', () => { + expectSpecifierMap( + `{ + "./foo": "/dotslash", + "../foo": "/dotdotslash", + "/foo": "/slash" + }`, + 'https://base.example/path1/path2/path3', + { + 'https://base.example/path1/path2/foo': [expect.toMatchURL('https://base.example/dotslash')], + 'https://base.example/path1/foo': [expect.toMatchURL('https://base.example/dotdotslash')], + 'https://base.example/foo': [expect.toMatchURL('https://base.example/slash')] + } + ); + }); + + it('should not absolutize strings prefixed with ./, ../, or / with a data: URL base', () => { + expectSpecifierMap( + `{ + "./foo": "https://example.com/dotslash", + "../foo": "https://example.com/dotdotslash", + "/foo": "https://example.com/slash" + }`, + 'data:text/html,test', + { + './foo': [expect.toMatchURL('https://example.com/dotslash')], + '../foo': [expect.toMatchURL('https://example.com/dotdotslash')], + '/foo': [expect.toMatchURL('https://example.com/slash')] + } + ); + }); + + it('should absolutize the literal strings ./, ../, or / with no suffix', () => { + expectSpecifierMap( + `{ + "./": "/dotslash/", + "../": "/dotdotslash/", + "/": "/slash/" + }`, + 'https://base.example/path1/path2/path3', + { + 'https://base.example/path1/path2/': [expect.toMatchURL('https://base.example/dotslash/')], + 'https://base.example/path1/': [expect.toMatchURL('https://base.example/dotdotslash/')], + 'https://base.example/': [expect.toMatchURL('https://base.example/slash/')] + } + ); + }); + + it('should treat percent-encoded variants of ./, ../, or / as bare specifiers', () => { + expectSpecifierMap( + `{ + "%2E/": "/dotSlash1/", + "%2E%2E/": "/dotDotSlash1/", + ".%2F": "/dotSlash2", + "..%2F": "/dotDotSlash2", + "%2F": "/slash2", + "%2E%2F": "/dotSlash3", + "%2E%2E%2F": "/dotDotSlash3" + }`, + 'https://base.example/path1/path2/path3', + { + '%2E/': [expect.toMatchURL('https://base.example/dotSlash1/')], + '%2E%2E/': [expect.toMatchURL('https://base.example/dotDotSlash1/')], + '.%2F': [expect.toMatchURL('https://base.example/dotSlash2')], + '..%2F': [expect.toMatchURL('https://base.example/dotDotSlash2')], + '%2F': [expect.toMatchURL('https://base.example/slash2')], + '%2E%2F': [expect.toMatchURL('https://base.example/dotSlash3')], + '%2E%2E%2F': [expect.toMatchURL('https://base.example/dotDotSlash3')] + } + ); + }); +}); + +describe('Absolute URL specifier keys', () => { + it('should only accept absolute URL specifier keys with fetch schemes, treating others as bare specifiers', () => { + expectSpecifierMap( + `{ + "about:good": "/about", + "blob:good": "/blob", + "data:good": "/data", + "file:///good": "/file", + "filesystem:good": "/filesystem", + "http://good/": "/http/", + "https://good/": "/https/", + "ftp://good/": "/ftp/", + "import:bad": "/import", + "mailto:bad": "/mailto", + "javascript:bad": "/javascript", + "wss:bad": "/wss" + }`, + 'https://base.example/path1/path2/path3', + { + 'about:good': [expect.toMatchURL('https://base.example/about')], + 'blob:good': [expect.toMatchURL('https://base.example/blob')], + 'data:good': [expect.toMatchURL('https://base.example/data')], + 'file:///good': [expect.toMatchURL('https://base.example/file')], + 'filesystem:good': [expect.toMatchURL('https://base.example/filesystem')], + 'http://good/': [expect.toMatchURL('https://base.example/http/')], + 'https://good/': [expect.toMatchURL('https://base.example/https/')], + 'ftp://good/': [expect.toMatchURL('https://base.example/ftp/')], + 'import:bad': [expect.toMatchURL('https://base.example/import')], + 'mailto:bad': [expect.toMatchURL('https://base.example/mailto')], + 'javascript:bad': [expect.toMatchURL('https://base.example/javascript')], + 'wss:bad': [expect.toMatchURL('https://base.example/wss')] + } + ); + }); + + it('should parse absolute URLs, treating unparseable ones as bare specifiers', () => { + expectSpecifierMap( + `{ + "https://ex ample.org/": "/unparseable1/", + "https://example.com:demo": "/unparseable2", + "http://[www.example.com]/": "/unparseable3/", + "https:example.org": "/invalidButParseable1/", + "https://///example.com///": "/invalidButParseable2/", + "https://example.net": "/prettyNormal/", + "https://ex%41mple.com/": "/percentDecoding/", + "https://example.com/%41": "/noPercentDecoding" + }`, + 'https://base.example/path1/path2/path3', + { + 'https://ex ample.org/': [expect.toMatchURL('https://base.example/unparseable1/')], + 'https://example.com:demo': [expect.toMatchURL('https://base.example/unparseable2')], + 'http://[www.example.com]/': [expect.toMatchURL('https://base.example/unparseable3/')], + 'https://example.org/': [expect.toMatchURL('https://base.example/invalidButParseable1/')], + 'https://example.com///': [expect.toMatchURL('https://base.example/invalidButParseable2/')], + 'https://example.net/': [expect.toMatchURL('https://base.example/prettyNormal/')], + 'https://example.com/': [expect.toMatchURL('https://base.example/percentDecoding/')], + 'https://example.com/%41': [expect.toMatchURL('https://base.example/noPercentDecoding')] + } + ); + }); + + it('should parse built-in module specifier keys, including with a "/"', () => { + expectSpecifierMap( + `{ + "${BLANK}": "/blank", + "${BLANK}/": "/blank/", + "${BLANK}/foo": "/blank/foo", + "${BLANK}\\\\foo": "/blank/backslashfoo" + }`, + 'https://base.example/path1/path2/path3', + { + [BLANK]: [expect.toMatchURL('https://base.example/blank')], + [`${BLANK}/`]: [expect.toMatchURL('https://base.example/blank/')], + [`${BLANK}/foo`]: [expect.toMatchURL('https://base.example/blank/foo')], + [`${BLANK}\\foo`]: [expect.toMatchURL('https://base.example/blank/backslashfoo')] + } + ); + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-builtins.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-builtins.js new file mode 100644 index 0000000..a9383df --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-builtins.js
@@ -0,0 +1,158 @@ +'use strict'; +const { URL } = require('url'); +const { parseFromString } = require('../lib/parser.js'); +const { resolve } = require('../lib/resolver.js'); +const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); + +const mapBaseURL = new URL('https://example.com/app/index.html'); +const scriptURL = new URL('https://example.com/js/app.mjs'); + +const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`; +const NONE = `${BUILT_IN_MODULE_SCHEME}:none`; + +function makeResolveUnderTest(mapString) { + const map = parseFromString(mapString, mapBaseURL); + return specifier => resolve(specifier, map, scriptURL); +} + +describe('Unmapped built-in module specifiers', () => { + const resolveUnderTest = makeResolveUnderTest(`{}`); + + it(`should resolve "${BLANK}" to "${BLANK}"`, () => { + expect(resolveUnderTest(BLANK)).toMatchURL(BLANK); + }); + + it(`should error resolving "${NONE}"`, () => { + expect(() => resolveUnderTest(NONE)).toThrow(TypeError); + }); +}); + +describe('Remapping built-in module specifiers', () => { + it('should remap built-in modules', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "${BLANK}": "./blank.mjs", + "${NONE}": "./none.mjs" + } + }`); + + expect(resolveUnderTest(BLANK)).toMatchURL('https://example.com/app/blank.mjs'); + expect(resolveUnderTest(NONE)).toMatchURL('https://example.com/app/none.mjs'); + }); + + it('should remap built-in modules with slashes', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "${BLANK}/": "./blank-slash/", + "${BLANK}/foo": "./blank-foo.mjs", + "${NONE}/": "./none-slash/", + "${NONE}/foo": "./none-foo.mjs" + } + }`); + + expect(resolveUnderTest(`${BLANK}/`)).toMatchURL('https://example.com/app/blank-slash/'); + expect(resolveUnderTest(`${BLANK}/foo`)).toMatchURL('https://example.com/app/blank-foo.mjs'); + expect(resolveUnderTest(`${BLANK}/bar`)).toMatchURL('https://example.com/app/blank-slash/bar'); + expect(resolveUnderTest(`${NONE}/`)).toMatchURL('https://example.com/app/none-slash/'); + expect(resolveUnderTest(`${NONE}/foo`)).toMatchURL('https://example.com/app/none-foo.mjs'); + expect(resolveUnderTest(`${NONE}/bar`)).toMatchURL('https://example.com/app/none-slash/bar'); + }); + + it('should remap built-in modules with fallbacks', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "${BLANK}": ["${BLANK}", "./blank.mjs"], + "${NONE}": ["${NONE}", "./none.mjs"] + } + }`); + + expect(resolveUnderTest(BLANK)).toMatchURL(BLANK); + expect(resolveUnderTest(NONE)).toMatchURL('https://example.com/app/none.mjs'); + }); + + it('should remap built-in modules with slashes and fallbacks', () => { + // NOTE: `${BLANK}/for-testing` is not per spec, just for these tests. + // See resolver.js. + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "${BLANK}/": ["${BLANK}/", "./blank/"], + "${BLANK}/for-testing": ["${BLANK}/for-testing", "./blank-for-testing-special"], + "${NONE}/": ["${NONE}/", "./none/"], + "${NONE}/foo": ["${NONE}/foo", "./none-foo-special"] + } + }`); + + // Built-in modules only resolve for exact matches, so this will trigger the fallback. + expect(resolveUnderTest(`${BLANK}/`)).toMatchURL('https://example.com/app/blank/'); + expect(resolveUnderTest(`${BLANK}/foo`)).toMatchURL('https://example.com/app/blank/foo'); + + // This would fall back in a real implementation; it's only because we've gone against + // spec in the reference implementation (to make this testable) that this maps. + expect(resolveUnderTest(`${BLANK}/for-testing`)).toMatchURL(`${BLANK}/for-testing`); + + expect(resolveUnderTest(`${NONE}/`)).toMatchURL('https://example.com/app/none/'); + expect(resolveUnderTest(`${NONE}/bar`)).toMatchURL('https://example.com/app/none/bar'); + expect(resolveUnderTest(`${NONE}/foo`)).toMatchURL('https://example.com/app/none-foo-special'); + }); +}); + +describe('Remapping to built-in modules', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "blank": "${BLANK}", + "/blank": "${BLANK}", + "/blank/": "${BLANK}/", + "/blank-for-testing": "${BLANK}/for-testing", + "none": "${NONE}", + "/none": "${NONE}" + } + }`); + + it(`should remap to "${BLANK}"`, () => { + expect(resolveUnderTest('blank')).toMatchURL(BLANK); + expect(resolveUnderTest('/blank')).toMatchURL(BLANK); + }); + + it(`should fail when remapping to "${BLANK}/"`, () => { + expect(() => resolveUnderTest('/blank/')).toThrow(TypeError); + }); + + it(`should remap to "${BLANK}/for-testing"`, () => { + expect(resolveUnderTest('/blank/for-testing')).toMatchURL(`${BLANK}/for-testing`); + expect(resolveUnderTest('/blank-for-testing')).toMatchURL(`${BLANK}/for-testing`); + }); + + it(`should remap to "${BLANK}" for URL-like specifiers`, () => { + expect(resolveUnderTest('/blank')).toMatchURL(BLANK); + expect(resolveUnderTest('https://example.com/blank')).toMatchURL(BLANK); + expect(resolveUnderTest('https://///example.com/blank')).toMatchURL(BLANK); + }); + + it(`should fail when remapping to "${NONE}"`, () => { + expect(() => resolveUnderTest('none')).toThrow(TypeError); + expect(() => resolveUnderTest('/none')).toThrow(TypeError); + }); +}); + +describe('Fallbacks with built-in module addresses', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "blank": [ + "${BLANK}", + "./blank-fallback.mjs" + ], + "none": [ + "${NONE}", + "./none-fallback.mjs" + ] + } + }`); + + it(`should resolve to "${BLANK}"`, () => { + expect(resolveUnderTest('blank')).toMatchURL(BLANK); + }); + + it(`should fall back past "${NONE}"`, () => { + expect(resolveUnderTest('none')).toMatchURL('https://example.com/app/none-fallback.mjs'); + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-not-yet-implemented.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-not-yet-implemented.js new file mode 100644 index 0000000..93d782f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-not-yet-implemented.js
@@ -0,0 +1,47 @@ +'use strict'; +const { URL } = require('url'); +const { parseFromString } = require('../lib/parser.js'); +const { resolve } = require('../lib/resolver.js'); +const { BUILT_IN_MODULE_SCHEME } = require('../lib/utils.js'); + +const mapBaseURL = new URL('https://example.com/app/index.html'); +const scriptURL = new URL('https://example.com/js/app.mjs'); + +const BLANK = `${BUILT_IN_MODULE_SCHEME}:blank`; + +function makeResolveUnderTest(mapString) { + const map = parseFromString(mapString, mapBaseURL); + return specifier => resolve(specifier, map, scriptURL); +} + +describe('Fallbacks that are not [built-in, fetch scheme]', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "bad1": [ + "${BLANK}", + "${BLANK}" + ], + "bad2": [ + "${BLANK}", + "/bad2-1.mjs", + "/bad2-2.mjs" + ], + "bad3": [ + "/bad3-1.mjs", + "/bad3-2.mjs" + ] + } + }`); + + it('should fail for [built-in, built-in]', () => { + expect(() => resolveUnderTest('bad1')).toThrow(/not yet implemented/); + }); + + it('should fail for [built-in, fetch scheme, fetch scheme]', () => { + expect(() => resolveUnderTest('bad2')).toThrow(/not yet implemented/); + }); + + it('should fail for [fetch scheme, fetch scheme]', () => { + expect(() => resolveUnderTest('bad3')).toThrow(/not yet implemented/); + }); +});
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-scopes.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-scopes.js new file mode 100644 index 0000000..ca19a66 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving-scopes.js
@@ -0,0 +1,230 @@ +'use strict'; +const { URL } = require('url'); +const { parseFromString } = require('../lib/parser.js'); +const { resolve } = require('../lib/resolver.js'); + +const mapBaseURL = new URL('https://example.com/app/index.html'); + +function makeResolveUnderTest(mapString) { + const map = parseFromString(mapString, mapBaseURL); + return (specifier, baseURL) => resolve(specifier, map, baseURL); +} + +describe('Mapped using scope instead of "imports"', () => { + const jsNonDirURL = new URL('https://example.com/js'); + const jsPrefixedURL = new URL('https://example.com/jsiscool'); + const inJSDirURL = new URL('https://example.com/js/app.mjs'); + const topLevelURL = new URL('https://example.com/app.mjs'); + + it('should fail when the mapping is to an empty array', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js/": { + "moment": null, + "lodash": [] + } + } + }`); + + expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('lodash', inJSDirURL)).toThrow(TypeError); + }); + + describe('Exact vs. prefix based matching', () => { + it('should match correctly when both are in the map', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js": { + "moment": "/only-triggered-by-exact/moment", + "moment/": "/only-triggered-by-exact/moment/" + }, + "/js/": { + "moment": "/triggered-by-any-subpath/moment", + "moment/": "/triggered-by-any-subpath/moment/" + } + } + }`); + + expect(resolveUnderTest('moment', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment'); + expect(resolveUnderTest('moment/foo', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment/foo'); + + expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment'); + expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment/foo'); + + expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError); + }); + + it('should match correctly when only an exact match is in the map', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js": { + "moment": "/only-triggered-by-exact/moment", + "moment/": "/only-triggered-by-exact/moment/" + } + } + }`); + + expect(resolveUnderTest('moment', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment'); + expect(resolveUnderTest('moment/foo', jsNonDirURL)).toMatchURL('https://example.com/only-triggered-by-exact/moment/foo'); + + expect(() => resolveUnderTest('moment', inJSDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', inJSDirURL)).toThrow(TypeError); + + expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError); + }); + + it('should match correctly when only a prefix match is in the map', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "scopes": { + "/js/": { + "moment": "/triggered-by-any-subpath/moment", + "moment/": "/triggered-by-any-subpath/moment/" + } + } + }`); + + expect(() => resolveUnderTest('moment', jsNonDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsNonDirURL)).toThrow(TypeError); + + expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment'); + expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/triggered-by-any-subpath/moment/foo'); + + expect(() => resolveUnderTest('moment', jsPrefixedURL)).toThrow(TypeError); + expect(() => resolveUnderTest('moment/foo', jsPrefixedURL)).toThrow(TypeError); + }); + }); + + describe('Package-like scenarios', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "moment": "/node_modules/moment/src/moment.js", + "moment/": "/node_modules/moment/src/", + "lodash-dot": "./node_modules/lodash-es/lodash.js", + "lodash-dot/": "./node_modules/lodash-es/", + "lodash-dotdot": "../node_modules/lodash-es/lodash.js", + "lodash-dotdot/": "../node_modules/lodash-es/" + }, + "scopes": { + "/": { + "moment": "/node_modules_3/moment/src/moment.js", + "vue": "/node_modules_3/vue/dist/vue.runtime.esm.js" + }, + "/js/": { + "lodash-dot": "./node_modules_2/lodash-es/lodash.js", + "lodash-dot/": "./node_modules_2/lodash-es/", + "lodash-dotdot": "../node_modules_2/lodash-es/lodash.js", + "lodash-dotdot/": "../node_modules_2/lodash-es/" + } + } + }`); + + it('should resolve scoped', () => { + expect(resolveUnderTest('lodash-dot', inJSDirURL)).toMatchURL('https://example.com/app/node_modules_2/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dotdot', inJSDirURL)).toMatchURL('https://example.com/node_modules_2/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dot/foo', inJSDirURL)).toMatchURL('https://example.com/app/node_modules_2/lodash-es/foo'); + expect(resolveUnderTest('lodash-dotdot/foo', inJSDirURL)).toMatchURL('https://example.com/node_modules_2/lodash-es/foo'); + }); + + it('should apply best scope match', () => { + expect(resolveUnderTest('moment', topLevelURL)).toMatchURL('https://example.com/node_modules_3/moment/src/moment.js'); + expect(resolveUnderTest('moment', inJSDirURL)).toMatchURL('https://example.com/node_modules_3/moment/src/moment.js'); + expect(resolveUnderTest('vue', inJSDirURL)).toMatchURL('https://example.com/node_modules_3/vue/dist/vue.runtime.esm.js'); + }); + + it('should fallback to "imports"', () => { + expect(resolveUnderTest('moment/foo', topLevelURL)).toMatchURL('https://example.com/node_modules/moment/src/foo'); + expect(resolveUnderTest('moment/foo', inJSDirURL)).toMatchURL('https://example.com/node_modules/moment/src/foo'); + expect(resolveUnderTest('lodash-dot', topLevelURL)).toMatchURL('https://example.com/app/node_modules/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dotdot', topLevelURL)).toMatchURL('https://example.com/node_modules/lodash-es/lodash.js'); + expect(resolveUnderTest('lodash-dot/foo', topLevelURL)).toMatchURL('https://example.com/app/node_modules/lodash-es/foo'); + expect(resolveUnderTest('lodash-dotdot/foo', topLevelURL)).toMatchURL('https://example.com/node_modules/lodash-es/foo'); + }); + + it('should still fail for package-like specifiers that are not declared', () => { + expect(() => resolveUnderTest('underscore/', inJSDirURL)).toThrow(TypeError); + expect(() => resolveUnderTest('underscore/foo', inJSDirURL)).toThrow(TypeError); + }); + }); + + describe('The scope inheritance example from the README', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/a-1.mjs", + "b": "/b-1.mjs", + "c": "/c-1.mjs" + }, + "scopes": { + "/scope2/": { + "a": "/a-2.mjs" + }, + "/scope2/scope3/": { + "b": "/b-3.mjs" + } + } + }`); + + const scope1URL = new URL('https://example.com/scope1/foo.mjs'); + const scope2URL = new URL('https://example.com/scope2/foo.mjs'); + const scope3URL = new URL('https://example.com/scope2/scope3/foo.mjs'); + + it('should fall back to "imports" when none match', () => { + expect(resolveUnderTest('a', scope1URL)).toMatchURL('https://example.com/a-1.mjs'); + expect(resolveUnderTest('b', scope1URL)).toMatchURL('https://example.com/b-1.mjs'); + expect(resolveUnderTest('c', scope1URL)).toMatchURL('https://example.com/c-1.mjs'); + }); + + it('should use a direct scope override', () => { + expect(resolveUnderTest('a', scope2URL)).toMatchURL('https://example.com/a-2.mjs'); + expect(resolveUnderTest('b', scope2URL)).toMatchURL('https://example.com/b-1.mjs'); + expect(resolveUnderTest('c', scope2URL)).toMatchURL('https://example.com/c-1.mjs'); + }); + + it('should use an indirect scope override', () => { + expect(resolveUnderTest('a', scope3URL)).toMatchURL('https://example.com/a-2.mjs'); + expect(resolveUnderTest('b', scope3URL)).toMatchURL('https://example.com/b-3.mjs'); + expect(resolveUnderTest('c', scope3URL)).toMatchURL('https://example.com/c-1.mjs'); + }); + }); + + describe('Relative URL scope keys', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/a-1.mjs", + "b": "/b-1.mjs", + "c": "/c-1.mjs" + }, + "scopes": { + "": { + "a": "/a-empty-string.mjs" + }, + "./": { + "b": "/b-dot-slash.mjs" + }, + "../": { + "c": "/c-dot-dot-slash.mjs" + } + } + }`); + const inSameDirAsMap = new URL('./foo.mjs', mapBaseURL); + const inDirAboveMap = new URL('../foo.mjs', mapBaseURL); + + it('should resolve an empty string scope using the import map URL', () => { + expect(resolveUnderTest('a', mapBaseURL)).toMatchURL('https://example.com/a-empty-string.mjs'); + expect(resolveUnderTest('a', inSameDirAsMap)).toMatchURL('https://example.com/a-1.mjs'); + }); + + it('should resolve a ./ scope using the import map URL\'s directory', () => { + expect(resolveUnderTest('b', mapBaseURL)).toMatchURL('https://example.com/b-dot-slash.mjs'); + expect(resolveUnderTest('b', inSameDirAsMap)).toMatchURL('https://example.com/b-dot-slash.mjs'); + }); + + it('should resolve a ../ scope using the import map URL\'s directory', () => { + expect(resolveUnderTest('c', mapBaseURL)).toMatchURL('https://example.com/c-dot-dot-slash.mjs'); + expect(resolveUnderTest('c', inSameDirAsMap)).toMatchURL('https://example.com/c-dot-dot-slash.mjs'); + expect(resolveUnderTest('c', inDirAboveMap)).toMatchURL('https://example.com/c-dot-dot-slash.mjs'); + }); + }); +}); +
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/resources/resolving.js b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving.js similarity index 76% rename from third_party/blink/web_tests/external/wpt/import-maps/resources/resolving.js rename to third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving.js index 0409962..29ee31cc 100644 --- a/third_party/blink/web_tests/external/wpt/import-maps/resources/resolving.js +++ b/third_party/blink/web_tests/external/wpt/import-maps/imported/resources/resolving.js
@@ -1,9 +1,4 @@ 'use strict'; - -// Imported from: -// https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js -// TODO: Upstream local changes. - const { URL } = require('url'); const { parseFromString } = require('../lib/parser.js'); const { resolve } = require('../lib/resolver.js'); @@ -89,7 +84,8 @@ "lodash-dot": "./node_modules/lodash-es/lodash.js", "lodash-dot/": "./node_modules/lodash-es/", "lodash-dotdot": "../node_modules/lodash-es/lodash.js", - "lodash-dotdot/": "../node_modules/lodash-es/" + "lodash-dotdot/": "../node_modules/lodash-es/", + "nowhere/": [] } }`); @@ -114,6 +110,10 @@ expect(() => resolveUnderTest('underscore/')).toThrow(TypeError); expect(() => resolveUnderTest('underscore/foo')).toThrow(TypeError); }); + + it('should fail for package submodules that map to nowhere', () => { + expect(() => resolveUnderTest('nowhere/foo')).toThrow(TypeError); + }); }); describe('Tricky specifiers', () => { @@ -149,7 +149,7 @@ describe('URL-like specifiers', () => { const resolveUnderTest = makeResolveUnderTest(`{ "imports": { - "/node_modules/als-polyfill/index.mjs": "@std/kv-storage", + "/node_modules/als-polyfill/index.mjs": "std:kv-storage", "/lib/foo.mjs": "./more/bar.mjs", "./dotrelative/foo.mjs": "/lib/dot.mjs", @@ -158,20 +158,17 @@ "/lib/no.mjs": null, "./dotrelative/no.mjs": [], - "/": "/lib/slash-only.mjs", - "./": "/lib/dotslash-only.mjs", + "/": "/lib/slash-only/", + "./": "/lib/dotslash-only/", + + "/test/": "/lib/url-trailing-slash/", + "./test/": "/lib/url-trailing-slash-dot/", "/test": "/lib/test1.mjs", "../test": "/lib/test2.mjs" } }`); - it('should remap to built-in modules', () => { - expect(resolveUnderTest('/node_modules/als-polyfill/index.mjs')).toMatchURL('import:@std/kv-storage'); - expect(resolveUnderTest('https://example.com/node_modules/als-polyfill/index.mjs')).toMatchURL('import:@std/kv-storage'); - expect(resolveUnderTest('https://///example.com/node_modules/als-polyfill/index.mjs')).toMatchURL('import:@std/kv-storage'); - }); - it('should remap to other URLs', () => { expect(resolveUnderTest('https://example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs'); expect(resolveUnderTest('https://///example.com/lib/foo.mjs')).toMatchURL('https://example.com/app/more/bar.mjs'); @@ -195,13 +192,18 @@ }); it('should remap URLs that are just composed from / and .', () => { - expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only.mjs'); - expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only.mjs'); - expect(resolveUnderTest('../')).toMatchURL('https://example.com/lib/slash-only.mjs'); + expect(resolveUnderTest('https://example.com/')).toMatchURL('https://example.com/lib/slash-only/'); + expect(resolveUnderTest('/')).toMatchURL('https://example.com/lib/slash-only/'); + expect(resolveUnderTest('../')).toMatchURL('https://example.com/lib/slash-only/'); - expect(resolveUnderTest('https://example.com/app/')).toMatchURL('https://example.com/lib/dotslash-only.mjs'); - expect(resolveUnderTest('/app/')).toMatchURL('https://example.com/lib/dotslash-only.mjs'); - expect(resolveUnderTest('../app/')).toMatchURL('https://example.com/lib/dotslash-only.mjs'); + expect(resolveUnderTest('https://example.com/app/')).toMatchURL('https://example.com/lib/dotslash-only/'); + expect(resolveUnderTest('/app/')).toMatchURL('https://example.com/lib/dotslash-only/'); + expect(resolveUnderTest('../app/')).toMatchURL('https://example.com/lib/dotslash-only/'); + }); + + it('should remap URLs that are prefix-matched by keys with trailing slashes', () => { + expect(resolveUnderTest('/test/foo.mjs')).toMatchURL('https://example.com/lib/url-trailing-slash/foo.mjs'); + expect(resolveUnderTest('https://example.com/app/test/foo.mjs')).toMatchURL('https://example.com/lib/url-trailing-slash-dot/foo.mjs'); }); it('should use the last entry\'s address when URL-like specifiers parse to the same absolute URL', () => { @@ -209,22 +211,60 @@ }); }); - describe('overlapping entries with trailing slashes', () => { - const resolveUnderTest = makeResolveUnderTest(`{ - "imports": { - "a": "/1", - "a/": "/2/", - "a/b": "/3", - "a/b/": "/4/" - } - }`); + describe('Overlapping entries with trailing slashes', () => { + it('should favor the most-specific key (no empty arrays)', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/1", + "a/": "/2/", + "a/b": "/3", + "a/b/": "/4/" + } + }`); - it('most-specific wins', () => { expect(resolveUnderTest('a')).toMatchURL('https://example.com/1'); expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/'); expect(resolveUnderTest('a/b')).toMatchURL('https://example.com/3'); expect(resolveUnderTest('a/b/')).toMatchURL('https://example.com/4/'); expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c'); }); + + it('should favor the most-specific key when empty arrays are involved for less-specific keys', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": [], + "a/": [], + "a/b": "/3", + "a/b/": "/4/" + } + }`); + + expect(() => resolveUnderTest('a')).toThrow(TypeError); + expect(() => resolveUnderTest('a/')).toThrow(TypeError); + expect(() => resolveUnderTest('a/x')).toThrow(TypeError); + expect(resolveUnderTest('a/b')).toMatchURL('https://example.com/3'); + expect(resolveUnderTest('a/b/')).toMatchURL('https://example.com/4/'); + expect(resolveUnderTest('a/b/c')).toMatchURL('https://example.com/4/c'); + expect(() => resolveUnderTest('a/x/c')).toThrow(TypeError); + }); + + it('should favor the most-specific key when empty arrays are involved for more-specific keys', () => { + const resolveUnderTest = makeResolveUnderTest(`{ + "imports": { + "a": "/1", + "a/": "/2/", + "a/b": [], + "a/b/": [] + } + }`); + + expect(resolveUnderTest('a')).toMatchURL('https://example.com/1'); + expect(resolveUnderTest('a/')).toMatchURL('https://example.com/2/'); + expect(resolveUnderTest('a/x')).toMatchURL('https://example.com/2/x'); + expect(() => resolveUnderTest('a/b')).toThrow(TypeError); + expect(() => resolveUnderTest('a/b/')).toThrow(TypeError); + expect(() => resolveUnderTest('a/b/c')).toThrow(TypeError); + expect(resolveUnderTest('a/x/c')).toMatchURL('https://example.com/2/x/c'); + }); }); });
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative.html b/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative.html deleted file mode 100644 index f2b09a7a..0000000 --- a/third_party/blink/web_tests/external/wpt/import-maps/resolving.tentative.html +++ /dev/null
@@ -1,81 +0,0 @@ -<!DOCTYPE html> -<html> -<script src="/resources/testharness.js"></script> -<script src="/resources/testharnessreport.js"></script> -<script> -setup({allow_uncaught_exception : true}); - -// Hacky glue code to run Jest-based tests as WPT tests. -// Only supports resolving.js. -function require(name) { - return { - 'URL': URL, - 'parseFromString': parseFromString, - 'resolve': resolve - }; -} - -function expect(v) { - return { - toMatchURL: expected => assert_equals(v, expected), - toThrow: expected => assert_throws(expected(), v) - }; -} - -let current_message = ''; -function describe(message, f) { - const old = current_message; - if (current_message !== '') { - current_message += ' / '; - } - current_message += message; - f(); - current_message = old; -} -function it(message, f) { - const old = current_message; - if (current_message !== '') { - current_message += ' / '; - } - current_message += message; - test(t => t.step_func(f)(), current_message); - current_message = old; -} - -// Creates a new Document (via <iframe>) and add an inline import map. -// Currently document.write() is used to make everything synchronous, which -// is just needed for running the existing Jest-based tests easily. -function parseFromString(mapString, mapBaseURL) { - const iframe = document.createElement('iframe'); - document.body.appendChild(iframe); - iframe.contentDocument.write(` - <base href="${mapBaseURL}"> - <script> - let isError = false; - function onError() { - isError = true; - } - </sc` + `ript> - <script type="importmap" onerror="onError()"> - ${mapString} - </sc` + `ript> - `); - iframe.contentDocument.close(); - return iframe; -} - -// URL resolution is tested using Chromium's `internals`. -// TODO(hiroshige): Remove the Chromium-specific dependency. -function resolve(specifier, map, baseURL) { - return internals.resolveModuleSpecifier(specifier, - baseURL, - map.contentDocument); -} - -</script> - -<!-- -resolving.js is -https://github.com/WICG/import-maps/blob/master/reference-implementation/__tests__/resolving.js ---> -<script type="module" src="resources/resolving.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/import-maps/resources/jest-test-helper.js b/third_party/blink/web_tests/external/wpt/import-maps/resources/jest-test-helper.js new file mode 100644 index 0000000..86556ed --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/import-maps/resources/jest-test-helper.js
@@ -0,0 +1,102 @@ +// Hacky glue code to run Jest-based tests as WPT tests. +// TODO(https://github.com/WICG/import-maps/issues/170): Consider better ways +// to write and run tests. + +setup({allow_uncaught_exception : true}); + +const exports = {}; + +function require(name) { + return Object.assign({ + 'URL': URL, + 'parseFromString': parseFromString, + 'resolve': resolve, + 'BUILT_IN_MODULE_SCHEME': 'std' + }, exports); +} + +function expect(v) { + return { + toMatchURL: expected => assert_equals(v, expected), + toThrow: expected => { + if (expected.test && expected.test('not yet implemented')) { + // We override /not yet implemented/ expectation. + assert_throws(TypeError(), v); + } else { + assert_throws(expected(), v); + } + }, + toEqual: expected => { + if (v.localName === 'iframe') { + // `v` is the result of parseFromString(), and thus toEqual() is + // expected to compare parsed import maps. + // We sort keys when stringifying for normalization. + const actualParsedImportMap = JSON.parse( + internals.getParsedImportMap(v.contentDocument)); + assert_equals( + JSON.stringify(actualParsedImportMap, + Object.keys(actualParsedImportMap).sort()), + JSON.stringify(expected.imports, + Object.keys(expected.imports).sort()) + ); + } else { + assert_object_equals(v, expected); + } + } + }; +} + +expect.toMatchURL = expected => expected; + +const test_harness_test = test; +test = it; + +let current_message = ''; +function describe(message, f) { + const old = current_message; + if (current_message !== '') { + current_message += ' / '; + } + current_message += message; + f(); + current_message = old; +} +function it(message, f) { + const old = current_message; + if (current_message !== '') { + current_message += ' / '; + } + current_message += message; + test_harness_test(t => t.step_func(f)(), current_message); + current_message = old; +} + +// Creates a new Document (via <iframe>) and add an inline import map. +// Currently document.write() is used to make everything synchronous, which +// is just needed for running the existing Jest-based tests easily. +function parseFromString(mapString, mapBaseURL) { + const iframe = document.createElement('iframe'); + document.body.appendChild(iframe); + iframe.contentDocument.write(` + <base href="${mapBaseURL}"> + <script> + let isError = false; + function onError() { + isError = true; + } + </sc` + `ript> + <script type="importmap" onerror="onError()"> + ${mapString} + </sc` + `ript> + `); + iframe.contentDocument.close(); + return iframe; +} + +// URL resolution is tested using Chromium's `internals`. +// TODO(hiroshige): Remove the Chromium-specific dependency. +function resolve(specifier, map, baseURL) { + return internals.resolveModuleSpecifier(specifier, + baseURL, + map.contentDocument); +}
diff --git a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html index abe753f..b551e76 100644 --- a/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html +++ b/third_party/blink/web_tests/external/wpt/largest-contentful-paint/observe-after-untrusted-scroll.html
@@ -19,7 +19,7 @@ 'The rendering timestamp should occur after script starts running.'); assert_greater_than_equal(performance.now(), entry.renderTime, 'The rendering timestamp should occur before the entry is dispatched to the observer.'); - assert_equals(entry.startTime, 0); + assert_equals(entry.startTime, entry.renderTime, 'startTime should equal renderTime'); assert_equals(entry.duration, 0); // blue.png is 133 x 106. assert_equals(entry.size, 14098);
diff --git a/third_party/blink/web_tests/external/wpt/lint.whitelist b/third_party/blink/web_tests/external/wpt/lint.whitelist index c344c3a..ea899da8 100644 --- a/third_party/blink/web_tests/external/wpt/lint.whitelist +++ b/third_party/blink/web_tests/external/wpt/lint.whitelist
@@ -808,7 +808,7 @@ # Tests that use WebKit/Blink testing APIs LAYOUTTESTS APIS: css/css-regions/interactivity/* -LAYOUTTESTS APIS: import-maps/resolving.tentative.html +LAYOUTTESTS APIS: import-maps/resources/jest-test-helper.js LAYOUTTESTS APIS: permissions/test-background-fetch-permission.html LAYOUTTESTS APIS: resources/chromium/generic_sensor_mocks.js LAYOUTTESTS APIS: resources/chromium/webxr-test.js
diff --git a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md index 3f9d75f5..1bd5832 100644 --- a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md +++ b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/README.md
@@ -1,4 +1,4 @@ This directory contains a built version of the [webidl2.js library](https://github.com/w3c/webidl2.js). -It is built by running `npx webpack --mode none` at the root of that repository. +It is built by running `npm run build-debug` at the root of that repository. The `webidl2.js.headers` file is a local addition to ensure the script is interpreted as UTF-8.
diff --git a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js index 9cb975a..900694b 100644 --- a/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js +++ b/third_party/blink/web_tests/external/wpt/resources/webidl2/lib/webidl2.js
@@ -103,10 +103,10 @@ /* harmony import */ var _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return _lib_webidl2_js__WEBPACK_IMPORTED_MODULE_0__["parse"]; }); -/* harmony import */ var _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14); +/* harmony import */ var _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(29); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "write", function() { return _lib_writer_js__WEBPACK_IMPORTED_MODULE_1__["write"]; }); -/* harmony import */ var _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(15); +/* harmony import */ var _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(30); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "validate", function() { return _lib_validator_js__WEBPACK_IMPORTED_MODULE_2__["validate"]; }); @@ -121,14 +121,20 @@ "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "parse", function() { return parse; }); -/* harmony import */ var _productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); -/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); -/* harmony import */ var _productions_base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); -/* harmony import */ var _productions_default_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8); -/* harmony import */ var _productions_enum_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(12); -/* harmony import */ var _productions_includes_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(13); -/* harmony import */ var _productions_type_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3); -/* harmony import */ var _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(9); +/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); +/* harmony import */ var _productions_enum_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4); +/* harmony import */ var _productions_includes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(16); +/* harmony import */ var _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); +/* harmony import */ var _productions_typedef_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(17); +/* harmony import */ var _productions_callback_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(18); +/* harmony import */ var _productions_interface_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(19); +/* harmony import */ var _productions_mixin_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(24); +/* harmony import */ var _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(25); +/* harmony import */ var _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(27); +/* harmony import */ var _productions_callback_interface_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(28); + + + @@ -148,469 +154,57 @@ function parseByTokens(tokeniser, options) { const source = tokeniser.source; - const ID = "identifier"; - function error(str) { tokeniser.error(str); } - function probe(type) { - return tokeniser.probe(type); - } - function consume(...candidates) { return tokeniser.consume(...candidates); } - function unconsume(position) { - return tokeniser.unconsume(position); - } - - class Constant extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse() { - const tokens = {}; - tokens.base = consume("const"); - if (!tokens.base) { - return; - } - let idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["primitive_type"])(tokeniser); - if (!idlType) { - const base = consume(ID) || error("No type for const"); - idlType = new _productions_type_js__WEBPACK_IMPORTED_MODULE_6__["Type"]({ source, tokens: { base } }); - } - if (probe("?")) { - error("Unexpected nullable constant type"); - } - idlType.type = "const-type"; - tokens.name = consume(ID) || error("No name for const"); - tokens.assign = consume("=") || error("No value assignment for const"); - tokens.value = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["const_value"])(tokeniser) || error("No value for const"); - tokens.termination = consume(";") || error("Unterminated const"); - const ret = new Constant({ source, tokens }); - ret.idlType = idlType; - return ret; - } - - get type() { - return "const"; - } - get name() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value); - } - get value() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["const_data"])(this.tokens.value); - } - } - - class CallbackFunction extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse(base) { - const tokens = { base }; - const ret = new CallbackFunction({ source, tokens }); - tokens.name = consume(ID) || error("No name for callback"); - tokeniser.current = ret; - tokens.assign = consume("=") || error("No assignment in callback"); - ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["return_type"])(tokeniser) || error("Missing return type"); - tokens.open = consume("(") || error("No arguments in callback"); - ret.arguments = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["argument_list"])(tokeniser); - tokens.close = consume(")") || error("Unterminated callback"); - tokens.termination = consume(";") || error("Unterminated callback"); - return ret; - } - - get type() { - return "callback"; - } - get name() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value); - } - } - function callback() { const callback = consume("callback"); if (!callback) return; - const tok = consume("interface"); - if (tok) { - return Interface.parse(tok, { callback }); + if (tokeniser.probe("interface")) { + return _productions_callback_interface_js__WEBPACK_IMPORTED_MODULE_10__["CallbackInterface"].parse(tokeniser, callback); } - return CallbackFunction.parse(callback); - } - - class Attribute extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse({ special, noInherit = false, readonly = false } = {}) { - const start_position = tokeniser.position; - const tokens = { special }; - const ret = new Attribute({ source, tokens }); - if (!special && !noInherit) { - tokens.special = consume("inherit"); - } - if (ret.special === "inherit" && probe("readonly")) { - error("Inherited attributes cannot be read-only"); - } - tokens.readonly = consume("readonly"); - if (readonly && !tokens.readonly && probe("attribute")) { - error("Attributes must be readonly in this context"); - } - tokens.base = consume("attribute"); - if (!tokens.base) { - unconsume(start_position); - return; - } - ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser, "attribute-type") || error("No type in attribute"); - switch (ret.idlType.generic) { - case "sequence": - case "record": error(`Attributes cannot accept ${ret.idlType.generic} types`); - } - tokens.name = consume(ID, "required") || error("No name in attribute"); - tokens.termination = consume(";") || error("Unterminated attribute"); - return ret; - } - - get type() { - return "attribute"; - } - get special() { - if (!this.tokens.special) { - return ""; - } - return this.tokens.special.value; - } - get readonly() { - return !!this.tokens.readonly; - } - get name() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value); - } - } - - class Operation extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse({ special, regular } = {}) { - const tokens = { special }; - const ret = new Operation({ source, tokens }); - if (special && special.value === "stringifier") { - tokens.termination = consume(";"); - if (tokens.termination) { - ret.arguments = []; - return ret; - } - } - if (!special && !regular) { - tokens.special = consume("getter", "setter", "deleter"); - } - ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["return_type"])(tokeniser) || error("Missing return type"); - tokens.name = consume(ID); - tokens.open = consume("(") || error("Invalid operation"); - ret.arguments = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["argument_list"])(tokeniser); - tokens.close = consume(")") || error("Unterminated operation"); - tokens.termination = consume(";") || error("Unterminated attribute"); - return ret; - } - - get type() { - return "operation"; - } - get name() { - const { name } = this.tokens; - if (!name) { - return ""; - } - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(name.value); - } - get special() { - if (!this.tokens.special) { - return ""; - } - return this.tokens.special.value; - } - } - - function static_member() { - const special = consume("static"); - if (!special) return; - const member = Attribute.parse({ special }) || - Operation.parse({ special }) || - error("No body in static member"); - return member; - } - - function stringifier() { - const special = consume("stringifier"); - if (!special) return; - const member = Attribute.parse({ special }) || - Operation.parse({ special }) || - error("Unterminated stringifier"); - return member; - } - - class IterableLike extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse() { - const start_position = tokeniser.position; - const tokens = {}; - const ret = new IterableLike({ source, tokens }); - tokens.readonly = consume("readonly"); - tokens.base = tokens.readonly ? - consume("maplike", "setlike") : - consume("iterable", "maplike", "setlike"); - if (!tokens.base) { - unconsume(start_position); - return; - } - - const { type } = ret; - const secondTypeRequired = type === "maplike"; - const secondTypeAllowed = secondTypeRequired || type === "iterable"; - - tokens.open = consume("<") || error(`Error parsing ${type} declaration`); - const first = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser) || error(`Error parsing ${type} declaration`); - ret.idlType = [first]; - if (secondTypeAllowed) { - first.tokens.separator = consume(","); - if (first.tokens.separator) { - ret.idlType.push(Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser)); - } - else if (secondTypeRequired) - error(`Missing second type argument in ${type} declaration`); - } - tokens.close = consume(">") || error(`Unterminated ${type} declaration`); - tokens.termination = consume(";") || error(`Missing semicolon after ${type} declaration`); - - return ret; - } - - get type() { - return this.tokens.base.value; - } - get readonly() { - return !!this.tokens.readonly; - } - } - - function inheritance() { - const colon = consume(":"); - if (!colon) { - return {}; - } - const inheritance = consume(ID) || error("No type in inheritance"); - return { colon, inheritance }; - } - - class Container extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse(instance, { type, inheritable, allowedMembers }) { - const { tokens } = instance; - tokens.name = consume(ID) || error("No name for interface"); - tokeniser.current = instance; - if (inheritable) { - Object.assign(tokens, inheritance()); - } - tokens.open = consume("{") || error(`Bodyless ${type}`); - instance.members = []; - while (true) { - tokens.close = consume("}"); - if (tokens.close) { - tokens.termination = consume(";") || error(`Missing semicolon after ${type}`); - return instance; - } - const ea = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__["ExtendedAttributes"].parse(tokeniser); - let mem; - for (const [parser, ...args] of allowedMembers) { - mem = parser(...args); - if (mem) { - break; - } - } - if (!mem) { - error("Unknown member"); - } - mem.extAttrs = ea; - instance.members.push(mem); - } - } - - get partial() { - return !!this.tokens.partial; - } - get name() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value); - } - get inheritance() { - if (!this.tokens.inheritance) { - return null; - } - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.inheritance.value); - } - } - - class Interface extends Container { - static parse(base, { callback = null, partial = null } = {}) { - const tokens = { callback, partial, base }; - return Container.parse(new Interface({ source, tokens }), { - type: "interface", - inheritable: !partial, - allowedMembers: [ - [Constant.parse], - [static_member], - [stringifier], - [IterableLike.parse], - [Attribute.parse], - [Operation.parse] - ] - }); - } - - get type() { - if (this.tokens.callback) { - return "callback interface"; - } - return "interface"; - } - } - - class Mixin extends Container { - static parse(base, { partial } = {}) { - const tokens = { partial, base }; - tokens.mixin = consume("mixin"); - if (!tokens.mixin) { - return; - } - return Container.parse(new Mixin({ source, tokens }), { - type: "interface mixin", - allowedMembers: [ - [Constant.parse], - [stringifier], - [Attribute.parse, { noInherit: true }], - [Operation.parse, { regular: true }] - ] - }); - } - - get type() { - return "interface mixin"; - } + return _productions_callback_js__WEBPACK_IMPORTED_MODULE_5__["CallbackFunction"].parse(tokeniser, callback); } function interface_(opts) { const base = consume("interface"); if (!base) return; - const ret = Mixin.parse(base, opts) || - Interface.parse(base, opts) || + const ret = _productions_mixin_js__WEBPACK_IMPORTED_MODULE_7__["Mixin"].parse(tokeniser, base, opts) || + _productions_interface_js__WEBPACK_IMPORTED_MODULE_6__["Interface"].parse(tokeniser, base, opts) || error("Interface has no proper body"); return ret; } - class Namespace extends Container { - static parse({ partial } = {}) { - const tokens = { partial }; - tokens.base = consume("namespace"); - if (!tokens.base) { - return; - } - return Container.parse(new Namespace({ source, tokens }), { - type: "namespace", - allowedMembers: [ - [Attribute.parse, { noInherit: true, readonly: true }], - [Operation.parse, { regular: true }] - ] - }); - } - - get type() { - return "namespace"; - } - } - function partial() { const partial = consume("partial"); if (!partial) return; - return Dictionary.parse({ partial }) || + return _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__["Dictionary"].parse(tokeniser, { partial }) || interface_({ partial }) || - Namespace.parse({ partial }) || + _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__["Namespace"].parse(tokeniser, { partial }) || error("Partial doesn't apply to anything"); } - class Dictionary extends Container { - static parse({ partial } = {}) { - const tokens = { partial }; - tokens.base = consume("dictionary"); - if (!tokens.base) { - return; - } - return Container.parse(new Dictionary({ source, tokens }), { - type: "dictionary", - inheritable: !partial, - allowedMembers: [ - [Field.parse], - ] - }); - } - - get type() { - return "dictionary"; - } - } - - class Field extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse() { - const tokens = {}; - const ret = new Field({ source, tokens }); - ret.extAttrs = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__["ExtendedAttributes"].parse(tokeniser); - tokens.required = consume("required"); - ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser, "dictionary-type") || error("No type for dictionary member"); - tokens.name = consume(ID) || error("No name for dictionary member"); - ret.default = _productions_default_js__WEBPACK_IMPORTED_MODULE_3__["Default"].parse(tokeniser); - if (tokens.required && ret.default) error("Required member must not have a default"); - tokens.termination = consume(";") || error("Unterminated dictionary member"); - return ret; - } - - get type() { - return "field"; - } - get name() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value); - } - get required() { - return !!this.tokens.required; - } - } - - class Typedef extends _productions_base_js__WEBPACK_IMPORTED_MODULE_2__["Base"] { - static parse() { - const tokens = {}; - const ret = new Typedef({ source, tokens }); - tokens.base = consume("typedef"); - if (!tokens.base) { - return; - } - ret.idlType = Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["type_with_extended_attributes"])(tokeniser, "typedef-type") || error("No type in typedef"); - tokens.name = consume(ID) || error("No name in typedef"); - tokeniser.current = ret; - tokens.termination = consume(";") || error("Unterminated typedef"); - return ret; - } - - get type() { - return "typedef"; - } - get name() { - return Object(_productions_helpers_js__WEBPACK_IMPORTED_MODULE_0__["unescape"])(this.tokens.name.value); - } - } - function definition() { return callback() || interface_() || partial() || - Dictionary.parse() || - _productions_enum_js__WEBPACK_IMPORTED_MODULE_4__["Enum"].parse(tokeniser) || - Typedef.parse() || - _productions_includes_js__WEBPACK_IMPORTED_MODULE_5__["Includes"].parse(tokeniser) || - Namespace.parse(); + _productions_dictionary_js__WEBPACK_IMPORTED_MODULE_8__["Dictionary"].parse(tokeniser) || + _productions_enum_js__WEBPACK_IMPORTED_MODULE_1__["Enum"].parse(tokeniser) || + _productions_typedef_js__WEBPACK_IMPORTED_MODULE_4__["Typedef"].parse(tokeniser) || + _productions_includes_js__WEBPACK_IMPORTED_MODULE_2__["Includes"].parse(tokeniser) || + _productions_namespace_js__WEBPACK_IMPORTED_MODULE_9__["Namespace"].parse(tokeniser); } function definitions() { if (!source.length) return []; const defs = []; while (true) { - const ea = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_7__["ExtendedAttributes"].parse(tokeniser); + const ea = _productions_extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__["ExtendedAttributes"].parse(tokeniser); const def = definition(); if (!def) { if (ea.length) error("Stray extended attributes"); @@ -631,7 +225,10 @@ } function parse(str, options = {}) { - const tokeniser = new _tokeniser_js__WEBPACK_IMPORTED_MODULE_1__["Tokeniser"](str); + const tokeniser = new _tokeniser_js__WEBPACK_IMPORTED_MODULE_0__["Tokeniser"](str); + if (typeof options.sourceName !== "undefined") { + tokeniser.source.name = options.sourceName; + } return parseByTokens(tokeniser, options); } @@ -642,374 +239,10 @@ "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unescape", function() { return unescape; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "list", function() { return list; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "const_value", function() { return const_value; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "const_data", function() { return const_data; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "primitive_type", function() { return primitive_type; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identifiers", function() { return identifiers; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "argument_list", function() { return argument_list; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "type_with_extended_attributes", function() { return type_with_extended_attributes; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "return_type", function() { return return_type; }); -/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3); -/* harmony import */ var _argument_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7); -/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); -/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(9); - - - - - -/** - * @param {string} identifier - */ -function unescape(identifier) { - return identifier.startsWith('_') ? identifier.slice(1) : identifier; -} - -/** - * Parses comma-separated list - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {object} args - * @param {Function} args.parser parser function for each item - * @param {boolean} [args.allowDangler] whether to allow dangling comma - * @param {string} [args.listName] the name to be shown on error messages - */ -function list(tokeniser, { parser, allowDangler, listName = "list" }) { - const first = parser(tokeniser); - if (!first) { - return []; - } - first.tokens.separator = tokeniser.consume(","); - const items = [first]; - while (first.tokens.separator) { - const item = parser(tokeniser); - if (!item) { - if (!allowDangler) { - tokeniser.error(`Trailing comma in ${listName}`); - } - break; - } - item.tokens.separator = tokeniser.consume(","); - items.push(item); - if (!item.tokens.separator) break; - } - return items; -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ -function const_value(tokeniser) { - return tokeniser.consume("true", "false", "Infinity", "-Infinity", "NaN", "decimal", "integer"); -} - -/** - * @param {object} token - * @param {string} token.type - * @param {string} token.value - */ -function const_data({ type, value }) { - switch (type) { - case "true": - case "false": - return { type: "boolean", value: type === "true" }; - case "Infinity": - case "-Infinity": - return { type: "Infinity", negative: type.startsWith("-") }; - case "[": - return { type: "sequence", value: [] }; - case "{": - return { type: "dictionary" }; - case "decimal": - case "integer": - return { type: "number", value }; - case "string": - return { type: "string", value: value.slice(1, -1) }; - default: - return { type }; - } -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ -function primitive_type(tokeniser) { - function integer_type() { - const prefix = tokeniser.consume("unsigned"); - const base = tokeniser.consume("short", "long"); - if (base) { - const postfix = tokeniser.consume("long"); - return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { prefix, base, postfix } }); - } - if (prefix) tokeniser.error("Failed to parse integer type"); - } - - function decimal_type() { - const prefix = tokeniser.consume("unrestricted"); - const base = tokeniser.consume("float", "double"); - if (base) { - return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { prefix, base } }); - } - if (prefix) tokeniser.error("Failed to parse float type"); - } - - const { source } = tokeniser; - const num_type = integer_type(tokeniser) || decimal_type(tokeniser); - if (num_type) return num_type; - const base = tokeniser.consume("boolean", "byte", "octet"); - if (base) { - return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { base } }); - } -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ -function identifiers(tokeniser) { - const ids = list(tokeniser, { parser: _token_js__WEBPACK_IMPORTED_MODULE_2__["Token"].parser(tokeniser, "identifier"), listName: "identifier list" }); - if (!ids.length) { - tokeniser.error("Expected identifiers but none found"); - } - return ids; -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ -function argument_list(tokeniser) { - return list(tokeniser, { parser: _argument_js__WEBPACK_IMPORTED_MODULE_1__["Argument"].parse, listName: "arguments list" }); -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} typeName - */ -function type_with_extended_attributes(tokeniser, typeName) { - const extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__["ExtendedAttributes"].parse(tokeniser); - const ret = _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"].parse(tokeniser, typeName); - if (ret) ret.extAttrs = extAttrs; - return ret; -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} typeName - */ -function return_type(tokeniser, typeName) { - const typ = _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"].parse(tokeniser, typeName || "return-type"); - if (typ) { - return typ; - } - const voidToken = tokeniser.consume("void"); - if (voidToken) { - const ret = new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source: tokeniser.source, tokens: { base: voidToken } }); - ret.type = "return-type"; - return ret; - } -} - - -/***/ }), -/* 3 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Type", function() { return Type; }); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); -/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); -/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5); - - - - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} typeName - */ -function generic_type(tokeniser, typeName) { - const base = tokeniser.consume("FrozenArray", "Promise", "sequence", "record"); - if (!base) { - return; - } - const ret = new Type({ source: tokeniser.source, tokens: { base } }); - ret.tokens.open = tokeniser.consume("<") || tokeniser.error(`No opening bracket after ${base.type}`); - switch (base.type) { - case "Promise": { - if (tokeniser.probe("[")) tokeniser.error("Promise type cannot have extended attribute"); - const subtype = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["return_type"])(tokeniser, typeName) || tokeniser.error("Missing Promise subtype"); - ret.subtype.push(subtype); - break; - } - case "sequence": - case "FrozenArray": { - const subtype = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, typeName) || tokeniser.error(`Missing ${base.type} subtype`); - ret.subtype.push(subtype); - break; - } - case "record": { - if (tokeniser.probe("[")) tokeniser.error("Record key cannot have extended attribute"); - const keyType = tokeniser.consume(..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"]) || tokeniser.error(`Record key must be one of: ${_tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"].join(", ")}`); - const keyIdlType = new Type({ source: tokeniser.source, tokens: { base: keyType }}); - keyIdlType.tokens.separator = tokeniser.consume(",") || tokeniser.error("Missing comma after record key type"); - keyIdlType.type = typeName; - const valueType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, typeName) || tokeniser.error("Error parsing generic type record"); - ret.subtype.push(keyIdlType, valueType); - break; - } - } - if (!ret.idlType) tokeniser.error(`Error parsing generic type ${base.type}`); - ret.tokens.close = tokeniser.consume(">") || tokeniser.error(`Missing closing bracket after ${base.type}`); - return ret; -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ -function type_suffix(tokeniser, obj) { - const nullable = tokeniser.consume("?"); - if (nullable) { - obj.tokens.nullable = nullable; - } - if (tokeniser.probe("?")) tokeniser.error("Can't nullable more than once"); -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} typeName - */ -function single_type(tokeniser, typeName) { - let ret = generic_type(tokeniser, typeName) || Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["primitive_type"])(tokeniser); - if (!ret) { - const base = tokeniser.consume("identifier", ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"]); - if (!base) { - return; - } - ret = new Type({ source: tokeniser.source, tokens: { base } }); - if (tokeniser.probe("<")) tokeniser.error(`Unsupported generic type ${base.value}`); - } - if (ret.generic === "Promise" && tokeniser.probe("?")) { - tokeniser.error("Promise type cannot be nullable"); - } - ret.type = typeName || null; - type_suffix(tokeniser, ret); - if (ret.nullable && ret.idlType === "any") tokeniser.error("Type `any` cannot be made nullable"); - return ret; -} - -/** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} type - */ -function union_type(tokeniser, type) { - const tokens = {}; - tokens.open = tokeniser.consume("("); - if (!tokens.open) return; - const ret = new Type({ source: tokeniser.source, tokens }); - ret.type = type || null; - while (true) { - const typ = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser) || tokeniser.error("No type after open parenthesis or 'or' in union type"); - if (typ.idlType === "any") tokeniser.error("Type `any` cannot be included in a union type"); - ret.subtype.push(typ); - const or = tokeniser.consume("or"); - if (or) { - typ.tokens.separator = or; - } - else break; - } - if (ret.idlType.length < 2) { - tokeniser.error("At least two types are expected in a union type but found less"); - } - tokens.close = tokeniser.consume(")") || tokeniser.error("Unterminated union type"); - type_suffix(tokeniser, ret); - return ret; -} - -class Type extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} typeName - */ - static parse(tokeniser, typeName) { - return single_type(tokeniser, typeName) || union_type(tokeniser, typeName); - } - - constructor({ source, tokens }) { - super({ source, tokens }); - Object.defineProperty(this, "subtype", { value: [] }); - this.extAttrs = []; - } - - get generic() { - if (this.subtype.length && this.tokens.base) { - return this.tokens.base.value; - } - return ""; - } - get nullable() { - return Boolean(this.tokens.nullable); - } - get union() { - return Boolean(this.subtype.length) && !this.tokens.base; - } - get idlType() { - if (this.subtype.length) { - return this.subtype; - } - // Adding prefixes/postfixes for "unrestricted float", etc. - const name = [ - this.tokens.prefix, - this.tokens.base, - this.tokens.postfix - ].filter(t => t).map(t => t.value).join(" "); - return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(name); - } -} - - -/***/ }), -/* 4 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Base", function() { return Base; }); -class Base { - constructor({ source, tokens }) { - Object.defineProperties(this, { - source: { value: source }, - tokens: { value: tokens } - }); - } - - toJSON() { - const json = { type: undefined, name: undefined, inheritance: undefined }; - let proto = this; - while (proto !== Object.prototype) { - const descMap = Object.getOwnPropertyDescriptors(proto); - for (const [key, value] of Object.entries(descMap)) { - if (value.enumerable || value.get) { - json[key] = this[key]; - } - } - proto = Object.getPrototypeOf(proto); - } - return json; - } -} - - -/***/ }), -/* 5 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stringTypes", function() { return stringTypes; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "argumentNameKeywords", function() { return argumentNameKeywords; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Tokeniser", function() { return Tokeniser; }); -/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3); // These regular expressions use the sticky flag so they will only match at @@ -1033,6 +266,7 @@ ]; const argumentNameKeywords = [ + "async", "attribute", "callback", "const", @@ -1062,13 +296,12 @@ "Infinity", "NaN", "Promise", + "async", "boolean", "byte", "double", "false", "float", - "implements", - "legacyiterable", "long", "mixin", "null", @@ -1235,10 +468,14 @@ } class WebIDLParseError extends Error { - constructor({ message, line, input, tokens }) { + constructor({ message, bareMessage, context, line, sourceName, input, tokens }) { super(message); + this.name = "WebIDLParseError"; // not to be mangled + this.bareMessage = bareMessage; + this.context = context; this.line = line; + this.sourceName = sourceName; this.input = input; this.tokens = tokens; } @@ -1246,7 +483,7 @@ /***/ }), -/* 6 */ +/* 3 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -1262,10 +499,14 @@ } /** + * @typedef {object} WebIDL2ErrorOptions + * @property {"error" | "warning"} level + * * @param {string} message error message - * @param {"Syntax" | "Validation"} type error type + * @param {"Syntax" | "Validation"} kind error type + * @param {WebIDL2ErrorOptions} [options] */ -function error(source, position, current, message, type) { +function error(source, position, current, message, kind, { level = "error" } = {}) { /** * @param {number} count */ @@ -1293,22 +534,28 @@ source.length > 1 ? source[position - 1].line : 1; - const precedingLine = lastLine( + const precedingLastLine = lastLine( tokensToText(sliceTokens(-maxTokens), { precedes: true }) ); const subsequentTokens = sliceTokens(maxTokens); const subsequentText = tokensToText(subsequentTokens); - const sobsequentLine = subsequentText.split("\n")[0]; + const subsequentFirstLine = subsequentText.split("\n")[0]; - const spaced = " ".repeat(precedingLine.length) + "^ " + message; - const contextualMessage = precedingLine + sobsequentLine + "\n" + spaced; + const spaced = " ".repeat(precedingLastLine.length) + "^"; + const sourceContext = precedingLastLine + subsequentFirstLine + "\n" + spaced; - const contextType = type === "Syntax" ? "since" : "inside"; - const grammaticalContext = current ? `, ${contextType} \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`` : ""; + const contextType = kind === "Syntax" ? "since" : "inside"; + const inSourceName = source.name ? ` in ${source.name}` : ""; + const grammaticalContext = (current && current.name) ? `, ${contextType} \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`` : ""; + const context = `${kind} error at line ${line}${inSourceName}${grammaticalContext}:\n${sourceContext}`; return { - message: `${type} error at line ${line}${grammaticalContext}:\n${contextualMessage}`, + message: `${context} ${message}`, + bareMessage: message, + context, line, + sourceName: source.name, + level, input: subsequentText, tokens: subsequentTokens }; @@ -1323,289 +570,23 @@ /** * @param {string} message error message + * @param {WebIDL2ErrorOptions} [options] */ -function validationError(source, token, current, message) { - return error(source, token.index, current, message, "Validation").message; +function validationError(source, token, current, message, options) { + return error(source, token.index, current, message, "Validation", options); } /***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Argument", function() { return Argument; }); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); -/* harmony import */ var _default_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8); -/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(9); -/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2); -/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5); - - - - - - -class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ - static parse(tokeniser) { - const start_position = tokeniser.position; - const tokens = {}; - const ret = new Argument({ source: tokeniser.source, tokens }); - ret.extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__["ExtendedAttributes"].parse(tokeniser); - tokens.optional = tokeniser.consume("optional"); - ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_3__["type_with_extended_attributes"])(tokeniser, "argument-type"); - if (!ret.idlType) { - return tokeniser.unconsume(start_position); - } - if (!tokens.optional) { - tokens.variadic = tokeniser.consume("..."); - } - tokens.name = tokeniser.consume("identifier", ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_4__["argumentNameKeywords"]); - if (!tokens.name) { - return tokeniser.unconsume(start_position); - } - ret.default = tokens.optional ? _default_js__WEBPACK_IMPORTED_MODULE_1__["Default"].parse(tokeniser) : null; - return ret; - } - - get optional() { - return !!this.tokens.optional; - } - get variadic() { - return !!this.tokens.variadic; - } - get name() { - return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_3__["unescape"])(this.tokens.name.value); - } -} - - -/***/ }), -/* 8 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Default", function() { return Default; }); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); -/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); - - - -class Default extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ - static parse(tokeniser) { - const assign = tokeniser.consume("="); - if (!assign) { - return null; - } - const def = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_value"])(tokeniser) || tokeniser.consume("string", "null", "[", "{") || tokeniser.error("No value for default"); - const expression = [def]; - if (def.type === "[") { - const close = tokeniser.consume("]") || tokeniser.error("Default sequence value must be empty"); - expression.push(close); - } else if (def.type === "{") { - const close = tokeniser.consume("}") || tokeniser.error("Default dictionary value must be empty"); - expression.push(close); - } - return new Default({ source: tokeniser.source, tokens: { assign }, expression }); - } - - constructor({ source, tokens, expression }) { - super({ source, tokens }); - Object.defineProperty(this, "expression", { value: expression }); - } - - get type() { - return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_data"])(this.expression[0]).type; - } - get value() { - return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_data"])(this.expression[0]).value; - } - get negative() { - return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_data"])(this.expression[0]).negative; - } -} - - -/***/ }), -/* 9 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtendedAttributes", function() { return ExtendedAttributes; }); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); -/* harmony import */ var _array_base_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10); -/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2); - - - - -class ExtendedAttributeParameters extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ - static parse(tokeniser) { - const tokens = { assign: tokeniser.consume("=") }; - const ret = new ExtendedAttributeParameters({ source: tokeniser.source, tokens }); - if (tokens.assign) { - tokens.secondaryName = tokeniser.consume("identifier", "decimal", "integer", "string"); - } - tokens.open = tokeniser.consume("("); - if (tokens.open) { - ret.list = ret.rhsType === "identifier-list" ? - // [Exposed=(Window,Worker)] - Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["identifiers"])(tokeniser) : - // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)] - Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["argument_list"])(tokeniser); - tokens.close = tokeniser.consume(")") || tokeniser.error("Unexpected token in extended attribute argument list"); - } else if (ret.hasRhs && !tokens.secondaryName) { - tokeniser.error("No right hand side to extended attribute assignment"); - } - return ret; - } - - get rhsType() { - return !this.tokens.assign ? null : - !this.tokens.secondaryName ? "identifier-list" : - this.tokens.secondaryName.type; - } -} - -class SimpleExtendedAttribute extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ - static parse(tokeniser) { - const name = tokeniser.consume("identifier"); - if (name) { - return new SimpleExtendedAttribute({ - tokens: { name }, - params: ExtendedAttributeParameters.parse(tokeniser) - }); - } - } - - constructor({ source, tokens, params }) { - super({ source, tokens }); - Object.defineProperty(this, "params", { value: params }); - } - - get type() { - return "extended-attribute"; - } - get name() { - return this.tokens.name.value; - } - get rhs() { - const { rhsType: type, tokens, list } = this.params; - if (!type) { - return null; - } - const value = type === "identifier-list" ? list : tokens.secondaryName.value; - return { type, value }; - } - get arguments() { - const { rhsType, list } = this.params; - if (!list || rhsType === "identifier-list") { - return []; - } - return list; - } -} - -// Note: we parse something simpler than the official syntax. It's all that ever -// seems to be used -class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__["ArrayBase"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - */ - static parse(tokeniser) { - const tokens = {}; - tokens.open = tokeniser.consume("["); - if (!tokens.open) return []; - const ret = new ExtendedAttributes({ source: tokeniser.source, tokens }); - ret.push(...Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["list"])(tokeniser, { - parser: SimpleExtendedAttribute.parse, - listName: "extended attribute" - })); - tokens.close = tokeniser.consume("]") || tokeniser.error("Unexpected closing token of extended attribute"); - if (!ret.length) { - tokeniser.error("Found an empty extended attribute"); - } - if (tokeniser.probe("[")) { - tokeniser.error("Illegal double extended attribute lists, consider merging them"); - } - return ret; - } -} - - -/***/ }), -/* 10 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayBase", function() { return ArrayBase; }); -class ArrayBase extends Array { - constructor({ source, tokens }) { - super(); - Object.defineProperties(this, { - source: { value: source }, - tokens: { value: tokens } - }); - } -} - - -/***/ }), -/* 11 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -__webpack_require__.r(__webpack_exports__); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Token", function() { return Token; }); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); - - -class Token extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { - /** - * @param {import("../tokeniser").Tokeniser} tokeniser - * @param {string} type - */ - static parser(tokeniser, type) { - return () => { - const value = tokeniser.consume(type); - if (value) { - return new Token({ source: tokeniser.source, tokens: { value } }); - } - }; - } - - get value() { - return this.tokens.value.value; - } -} - - -/***/ }), -/* 12 */ +/* 4 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Enum", function() { return Enum; }); -/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2); -/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5); +/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(13); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(7); @@ -1668,14 +649,936 @@ /***/ }), +/* 5 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "unescape", function() { return unescape; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "list", function() { return list; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "const_value", function() { return const_value; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "const_data", function() { return const_data; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "primitive_type", function() { return primitive_type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "identifiers", function() { return identifiers; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "argument_list", function() { return argument_list; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "type_with_extended_attributes", function() { return type_with_extended_attributes; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "return_type", function() { return return_type; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "stringifier", function() { return stringifier; }); +/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6); +/* harmony import */ var _argument_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(9); +/* harmony import */ var _token_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(13); +/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(11); +/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(14); +/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(15); + + + + + + + +/** + * @param {string} identifier + */ +function unescape(identifier) { + return identifier.startsWith('_') ? identifier.slice(1) : identifier; +} + +/** + * Parses comma-separated list + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {object} args + * @param {Function} args.parser parser function for each item + * @param {boolean} [args.allowDangler] whether to allow dangling comma + * @param {string} [args.listName] the name to be shown on error messages + */ +function list(tokeniser, { parser, allowDangler, listName = "list" }) { + const first = parser(tokeniser); + if (!first) { + return []; + } + first.tokens.separator = tokeniser.consume(","); + const items = [first]; + while (first.tokens.separator) { + const item = parser(tokeniser); + if (!item) { + if (!allowDangler) { + tokeniser.error(`Trailing comma in ${listName}`); + } + break; + } + item.tokens.separator = tokeniser.consume(","); + items.push(item); + if (!item.tokens.separator) break; + } + return items; +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function const_value(tokeniser) { + return tokeniser.consume("true", "false", "Infinity", "-Infinity", "NaN", "decimal", "integer"); +} + +/** + * @param {object} token + * @param {string} token.type + * @param {string} token.value + */ +function const_data({ type, value }) { + switch (type) { + case "true": + case "false": + return { type: "boolean", value: type === "true" }; + case "Infinity": + case "-Infinity": + return { type: "Infinity", negative: type.startsWith("-") }; + case "[": + return { type: "sequence", value: [] }; + case "{": + return { type: "dictionary" }; + case "decimal": + case "integer": + return { type: "number", value }; + case "string": + return { type: "string", value: value.slice(1, -1) }; + default: + return { type }; + } +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function primitive_type(tokeniser) { + function integer_type() { + const prefix = tokeniser.consume("unsigned"); + const base = tokeniser.consume("short", "long"); + if (base) { + const postfix = tokeniser.consume("long"); + return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { prefix, base, postfix } }); + } + if (prefix) tokeniser.error("Failed to parse integer type"); + } + + function decimal_type() { + const prefix = tokeniser.consume("unrestricted"); + const base = tokeniser.consume("float", "double"); + if (base) { + return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { prefix, base } }); + } + if (prefix) tokeniser.error("Failed to parse float type"); + } + + const { source } = tokeniser; + const num_type = integer_type(tokeniser) || decimal_type(tokeniser); + if (num_type) return num_type; + const base = tokeniser.consume("boolean", "byte", "octet"); + if (base) { + return new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source, tokens: { base } }); + } +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function identifiers(tokeniser) { + const ids = list(tokeniser, { parser: _token_js__WEBPACK_IMPORTED_MODULE_2__["Token"].parser(tokeniser, "identifier"), listName: "identifier list" }); + if (!ids.length) { + tokeniser.error("Expected identifiers but none found"); + } + return ids; +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function argument_list(tokeniser) { + return list(tokeniser, { parser: _argument_js__WEBPACK_IMPORTED_MODULE_1__["Argument"].parse, listName: "arguments list" }); +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} typeName + */ +function type_with_extended_attributes(tokeniser, typeName) { + const extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_3__["ExtendedAttributes"].parse(tokeniser); + const ret = _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"].parse(tokeniser, typeName); + if (ret) ret.extAttrs = extAttrs; + return ret; +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} typeName + */ +function return_type(tokeniser, typeName) { + const typ = _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"].parse(tokeniser, typeName || "return-type"); + if (typ) { + return typ; + } + const voidToken = tokeniser.consume("void"); + if (voidToken) { + const ret = new _type_js__WEBPACK_IMPORTED_MODULE_0__["Type"]({ source: tokeniser.source, tokens: { base: voidToken } }); + ret.type = "return-type"; + return ret; + } +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function stringifier(tokeniser) { + const special = tokeniser.consume("stringifier"); + if (!special) return; + const member = _attribute_js__WEBPACK_IMPORTED_MODULE_5__["Attribute"].parse(tokeniser, { special }) || + _operation_js__WEBPACK_IMPORTED_MODULE_4__["Operation"].parse(tokeniser, { special }) || + tokeniser.error("Unterminated stringifier"); + return member; +} + + +/***/ }), +/* 6 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Type", function() { return Type; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3); +/* harmony import */ var _validators_helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(8); + + + + + + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} typeName + */ +function generic_type(tokeniser, typeName) { + const base = tokeniser.consume("FrozenArray", "Promise", "sequence", "record"); + if (!base) { + return; + } + const ret = new Type({ source: tokeniser.source, tokens: { base } }); + ret.tokens.open = tokeniser.consume("<") || tokeniser.error(`No opening bracket after ${base.type}`); + switch (base.type) { + case "Promise": { + if (tokeniser.probe("[")) tokeniser.error("Promise type cannot have extended attribute"); + const subtype = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["return_type"])(tokeniser, typeName) || tokeniser.error("Missing Promise subtype"); + ret.subtype.push(subtype); + break; + } + case "sequence": + case "FrozenArray": { + const subtype = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, typeName) || tokeniser.error(`Missing ${base.type} subtype`); + ret.subtype.push(subtype); + break; + } + case "record": { + if (tokeniser.probe("[")) tokeniser.error("Record key cannot have extended attribute"); + const keyType = tokeniser.consume(..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"]) || tokeniser.error(`Record key must be one of: ${_tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"].join(", ")}`); + const keyIdlType = new Type({ source: tokeniser.source, tokens: { base: keyType }}); + keyIdlType.tokens.separator = tokeniser.consume(",") || tokeniser.error("Missing comma after record key type"); + keyIdlType.type = typeName; + const valueType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, typeName) || tokeniser.error("Error parsing generic type record"); + ret.subtype.push(keyIdlType, valueType); + break; + } + } + if (!ret.idlType) tokeniser.error(`Error parsing generic type ${base.type}`); + ret.tokens.close = tokeniser.consume(">") || tokeniser.error(`Missing closing bracket after ${base.type}`); + return ret; +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function type_suffix(tokeniser, obj) { + const nullable = tokeniser.consume("?"); + if (nullable) { + obj.tokens.nullable = nullable; + } + if (tokeniser.probe("?")) tokeniser.error("Can't nullable more than once"); +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} typeName + */ +function single_type(tokeniser, typeName) { + let ret = generic_type(tokeniser, typeName) || Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["primitive_type"])(tokeniser); + if (!ret) { + const base = tokeniser.consume("identifier", ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_2__["stringTypes"]); + if (!base) { + return; + } + ret = new Type({ source: tokeniser.source, tokens: { base } }); + if (tokeniser.probe("<")) tokeniser.error(`Unsupported generic type ${base.value}`); + } + if (ret.generic === "Promise" && tokeniser.probe("?")) { + tokeniser.error("Promise type cannot be nullable"); + } + ret.type = typeName || null; + type_suffix(tokeniser, ret); + if (ret.nullable && ret.idlType === "any") tokeniser.error("Type `any` cannot be made nullable"); + return ret; +} + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} type + */ +function union_type(tokeniser, type) { + const tokens = {}; + tokens.open = tokeniser.consume("("); + if (!tokens.open) return; + const ret = new Type({ source: tokeniser.source, tokens }); + ret.type = type || null; + while (true) { + const typ = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser) || tokeniser.error("No type after open parenthesis or 'or' in union type"); + if (typ.idlType === "any") tokeniser.error("Type `any` cannot be included in a union type"); + ret.subtype.push(typ); + const or = tokeniser.consume("or"); + if (or) { + typ.tokens.separator = or; + } + else break; + } + if (ret.idlType.length < 2) { + tokeniser.error("At least two types are expected in a union type but found less"); + } + tokens.close = tokeniser.consume(")") || tokeniser.error("Unterminated union type"); + type_suffix(tokeniser, ret); + return ret; +} + +class Type extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} typeName + */ + static parse(tokeniser, typeName) { + return single_type(tokeniser, typeName) || union_type(tokeniser, typeName); + } + + constructor({ source, tokens }) { + super({ source, tokens }); + Object.defineProperty(this, "subtype", { value: [] }); + this.extAttrs = []; + } + + get generic() { + if (this.subtype.length && this.tokens.base) { + return this.tokens.base.value; + } + return ""; + } + get nullable() { + return Boolean(this.tokens.nullable); + } + get union() { + return Boolean(this.subtype.length) && !this.tokens.base; + } + get idlType() { + if (this.subtype.length) { + return this.subtype; + } + // Adding prefixes/postfixes for "unrestricted float", etc. + const name = [ + this.tokens.prefix, + this.tokens.base, + this.tokens.postfix + ].filter(t => t).map(t => t.value).join(" "); + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(name); + } + + *validate(defs) { + /* + * If a union is nullable, its subunions cannot include a dictionary + * If not, subunions may include dictionaries if each union is not nullable + */ + const typedef = !this.union && defs.unique.get(this.idlType); + const target = + this.union ? this : + (typedef && typedef.type === "typedef") ? typedef.idlType : + undefined; + if (target && this.nullable) { + // do not allow any dictionary + const reference = Object(_validators_helpers_js__WEBPACK_IMPORTED_MODULE_4__["idlTypeIncludesDictionary"])(target, defs); + if (reference) { + const targetToken = (this.union ? reference : this).tokens.base; + const message = `Nullable union cannot include a dictionary type`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_3__["validationError"])(this.source, targetToken, this, message); + } + } else { + // allow some dictionary + for (const subtype of this.subtype) { + yield* subtype.validate(defs); + } + } + } +} + + +/***/ }), +/* 7 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Base", function() { return Base; }); +class Base { + constructor({ source, tokens }) { + Object.defineProperties(this, { + source: { value: source }, + tokens: { value: tokens } + }); + } + + toJSON() { + const json = { type: undefined, name: undefined, inheritance: undefined }; + let proto = this; + while (proto !== Object.prototype) { + const descMap = Object.getOwnPropertyDescriptors(proto); + for (const [key, value] of Object.entries(descMap)) { + if (value.enumerable || value.get) { + json[key] = this[key]; + } + } + proto = Object.getPrototypeOf(proto); + } + return json; + } +} + + +/***/ }), +/* 8 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dictionaryWithinUnion", function() { return dictionaryWithinUnion; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "idlTypeIncludesDictionary", function() { return idlTypeIncludesDictionary; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "referencesTypedef", function() { return referencesTypedef; }); +/** + * Yields direct references to dictionary within union. + */ +function* dictionaryWithinUnion(subtypes, defs) { + for (const subtype of subtypes) { + const def = defs.unique.get(subtype.idlType); + if (def && def.type === "dictionary") { + yield subtype; + } + } +} + +/** + * @return the type reference that ultimately includes dictionary. + */ +function idlTypeIncludesDictionary(idlType, defs) { + if (!idlType.union) { + const def = defs.unique.get(idlType.idlType); + if (!def) { + return; + } + if (def.type === "typedef") { + const { typedefIncludesDictionary} = defs.cache; + if (typedefIncludesDictionary.has(def)) { + // Note that this also halts when it met indeterminate state + // to prevent infinite recursion + return typedefIncludesDictionary.get(def); + } + defs.cache.typedefIncludesDictionary.set(def, undefined); // indeterminate state + const result = idlTypeIncludesDictionary(def.idlType, defs); + defs.cache.typedefIncludesDictionary.set(def, result); + if (result) { + return idlType; + } + } + if (def.type === "dictionary") { + return idlType; + } + } + for (const subtype of idlType.subtype) { + const result = idlTypeIncludesDictionary(subtype, defs); + if (result) { + if (subtype.union) { + return result; + } + return subtype; + } + } +} + +/** + * @return true if the idlType directly references a typedef. + */ +function referencesTypedef(idlType, defs) { + const result = defs.unique.get(idlType.idlType); + return result && result.type === "typedef"; +} + + +/***/ }), +/* 9 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Argument", function() { return Argument; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _default_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(10); +/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5); +/* harmony import */ var _tokeniser_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(2); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(3); +/* harmony import */ var _validators_helpers_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(8); + + + + + + + + +class Argument extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const start_position = tokeniser.position; + const tokens = {}; + const ret = new Argument({ source: tokeniser.source, tokens }); + ret.extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__["ExtendedAttributes"].parse(tokeniser); + tokens.optional = tokeniser.consume("optional"); + ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_3__["type_with_extended_attributes"])(tokeniser, "argument-type"); + if (!ret.idlType) { + return tokeniser.unconsume(start_position); + } + if (!tokens.optional) { + tokens.variadic = tokeniser.consume("..."); + } + tokens.name = tokeniser.consume("identifier", ..._tokeniser_js__WEBPACK_IMPORTED_MODULE_4__["argumentNameKeywords"]); + if (!tokens.name) { + return tokeniser.unconsume(start_position); + } + ret.default = tokens.optional ? _default_js__WEBPACK_IMPORTED_MODULE_1__["Default"].parse(tokeniser) : null; + return ret; + } + + get type() { + return "argument"; + } + get optional() { + return !!this.tokens.optional; + } + get variadic() { + return !!this.tokens.variadic; + } + get name() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_3__["unescape"])(this.tokens.name.value); + } + + *validate(defs) { + yield* this.idlType.validate(defs); + if (Object(_validators_helpers_js__WEBPACK_IMPORTED_MODULE_6__["idlTypeIncludesDictionary"])(this.idlType, defs)) { + if (this.optional && !this.default) { + const message = `Optional dictionary arguments must have a default value of \`{}\`.`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_5__["validationError"])(this.source, this.tokens.name, this, message); + } + if (this.idlType.nullable) { + const message = `Dictionary arguments cannot be nullable.`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_5__["validationError"])(this.source, this.tokens.name, this, message); + } + } + } +} + + +/***/ }), +/* 10 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Default", function() { return Default; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); + + + +class Default extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const assign = tokeniser.consume("="); + if (!assign) { + return null; + } + const def = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_value"])(tokeniser) || tokeniser.consume("string", "null", "[", "{") || tokeniser.error("No value for default"); + const expression = [def]; + if (def.type === "[") { + const close = tokeniser.consume("]") || tokeniser.error("Default sequence value must be empty"); + expression.push(close); + } else if (def.type === "{") { + const close = tokeniser.consume("}") || tokeniser.error("Default dictionary value must be empty"); + expression.push(close); + } + return new Default({ source: tokeniser.source, tokens: { assign }, expression }); + } + + constructor({ source, tokens, expression }) { + super({ source, tokens }); + Object.defineProperty(this, "expression", { value: expression }); + } + + get type() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_data"])(this.expression[0]).type; + } + get value() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_data"])(this.expression[0]).value; + } + get negative() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["const_data"])(this.expression[0]).negative; + } +} + + +/***/ }), +/* 11 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ExtendedAttributes", function() { return ExtendedAttributes; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _array_base_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(12); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3); + + + + + +class ExtendedAttributeParameters extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const tokens = { assign: tokeniser.consume("=") }; + const ret = new ExtendedAttributeParameters({ source: tokeniser.source, tokens }); + if (tokens.assign) { + tokens.secondaryName = tokeniser.consume("identifier", "decimal", "integer", "string"); + } + tokens.open = tokeniser.consume("("); + if (tokens.open) { + ret.list = ret.rhsType === "identifier-list" ? + // [Exposed=(Window,Worker)] + Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["identifiers"])(tokeniser) : + // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)] + Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["argument_list"])(tokeniser); + tokens.close = tokeniser.consume(")") || tokeniser.error("Unexpected token in extended attribute argument list"); + } else if (ret.hasRhs && !tokens.secondaryName) { + tokeniser.error("No right hand side to extended attribute assignment"); + } + return ret; + } + + get rhsType() { + return !this.tokens.assign ? null : + !this.tokens.secondaryName ? "identifier-list" : + this.tokens.secondaryName.type; + } +} + +class SimpleExtendedAttribute extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const name = tokeniser.consume("identifier"); + if (name) { + return new SimpleExtendedAttribute({ + source: tokeniser.source, + tokens: { name }, + params: ExtendedAttributeParameters.parse(tokeniser) + }); + } + } + + constructor({ source, tokens, params }) { + super({ source, tokens }); + Object.defineProperty(this, "params", { value: params }); + } + + get type() { + return "extended-attribute"; + } + get name() { + return this.tokens.name.value; + } + get rhs() { + const { rhsType: type, tokens, list } = this.params; + if (!type) { + return null; + } + const value = type === "identifier-list" ? list : tokens.secondaryName.value; + return { type, value }; + } + get arguments() { + const { rhsType, list } = this.params; + if (!list || rhsType === "identifier-list") { + return []; + } + return list; + } + + *validate(defs) { + if (this.name === "NoInterfaceObject") { + const message = `\`[NoInterfaceObject]\` extended attribute is an \ +undesirable feature that may be removed from Web IDL in the future. Refer to the \ +[relevant upstream PR](https://github.com/heycam/webidl/pull/609) for more \ +information.`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_3__["validationError"])(this.source, this.tokens.name, this, message, { level: "warning" }); + } + for (const arg of this.arguments) { + yield* arg.validate(defs); + } + } +} + +// Note: we parse something simpler than the official syntax. It's all that ever +// seems to be used +class ExtendedAttributes extends _array_base_js__WEBPACK_IMPORTED_MODULE_1__["ArrayBase"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const tokens = {}; + tokens.open = tokeniser.consume("["); + if (!tokens.open) return new ExtendedAttributes({}); + const ret = new ExtendedAttributes({ source: tokeniser.source, tokens }); + ret.push(...Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["list"])(tokeniser, { + parser: SimpleExtendedAttribute.parse, + listName: "extended attribute" + })); + tokens.close = tokeniser.consume("]") || tokeniser.error("Unexpected closing token of extended attribute"); + if (!ret.length) { + tokeniser.error("Found an empty extended attribute"); + } + if (tokeniser.probe("[")) { + tokeniser.error("Illegal double extended attribute lists, consider merging them"); + } + return ret; + } + + *validate(defs) { + for (const extAttr of this) { + yield* extAttr.validate(defs); + } + } +} + + +/***/ }), +/* 12 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayBase", function() { return ArrayBase; }); +class ArrayBase extends Array { + constructor({ source, tokens }) { + super(); + Object.defineProperties(this, { + source: { value: source }, + tokens: { value: tokens } + }); + } +} + + +/***/ }), /* 13 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Token", function() { return Token; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); + + +class Token extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + * @param {string} type + */ + static parser(tokeniser, type) { + return () => { + const value = tokeniser.consume(type); + if (value) { + return new Token({ source: tokeniser.source, tokens: { value } }); + } + }; + } + + get value() { + return this.tokens.value.value; + } +} + + +/***/ }), +/* 14 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Operation", function() { return Operation; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); + + + +class Operation extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + */ + static parse(tokeniser, { special, regular } = {}) { + const tokens = { special }; + const ret = new Operation({ source: tokeniser.source, tokens }); + if (special && special.value === "stringifier") { + tokens.termination = tokeniser.consume(";"); + if (tokens.termination) { + ret.arguments = []; + return ret; + } + } + if (!special && !regular) { + tokens.special = tokeniser.consume("getter", "setter", "deleter"); + } + ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["return_type"])(tokeniser) || tokeniser.error("Missing return type"); + tokens.name = tokeniser.consume("identifier", "includes"); + tokens.open = tokeniser.consume("(") || tokeniser.error("Invalid operation"); + ret.arguments = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["argument_list"])(tokeniser); + tokens.close = tokeniser.consume(")") || tokeniser.error("Unterminated operation"); + tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated operation, expected `;`"); + return ret; + } + + get type() { + return "operation"; + } + get name() { + const { name } = this.tokens; + if (!name) { + return ""; + } + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(name.value); + } + get special() { + if (!this.tokens.special) { + return ""; + } + return this.tokens.special.value; + } + + *validate(defs) { + if (this.idlType) { + yield* this.idlType.validate(defs); + } + for (const argument of this.arguments) { + yield* argument.validate(defs); + } + } +} + + +/***/ }), +/* 15 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Attribute", function() { return Attribute; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); + + + +class Attribute extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + */ + static parse(tokeniser, { special, noInherit = false, readonly = false } = {}) { + const start_position = tokeniser.position; + const tokens = { special }; + const ret = new Attribute({ source: tokeniser.source, tokens }); + if (!special && !noInherit) { + tokens.special = tokeniser.consume("inherit"); + } + if (ret.special === "inherit" && tokeniser.probe("readonly")) { + tokeniser.error("Inherited attributes cannot be read-only"); + } + tokens.readonly = tokeniser.consume("readonly"); + if (readonly && !tokens.readonly && tokeniser.probe("attribute")) { + tokeniser.error("Attributes must be readonly in this context"); + } + tokens.base = tokeniser.consume("attribute"); + if (!tokens.base) { + tokeniser.unconsume(start_position); + return; + } + ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, "attribute-type") || tokeniser.error("Attribute lacks a type"); + switch (ret.idlType.generic) { + case "sequence": + case "record": tokeniser.error(`Attributes cannot accept ${ret.idlType.generic} types`); + } + tokens.name = tokeniser.consume("identifier", "async", "required") || tokeniser.error("Attribute lacks a name"); + tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated attribute, expected `;`"); + return ret; + } + + get type() { + return "attribute"; + } + get special() { + if (!this.tokens.special) { + return ""; + } + return this.tokens.special.value; + } + get readonly() { + return !!this.tokens.readonly; + } + get name() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(this.tokens.name.value); + } + + *validate(defs) { + yield* this.idlType.validate(defs); + } +} + + +/***/ }), +/* 16 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Includes", function() { return Includes; }); -/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4); -/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); @@ -1712,7 +1615,647 @@ /***/ }), -/* 14 */ +/* 17 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Typedef", function() { return Typedef; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); + + + +class Typedef extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const tokens = {}; + const ret = new Typedef({ source: tokeniser.source, tokens }); + tokens.base = tokeniser.consume("typedef"); + if (!tokens.base) { + return; + } + ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, "typedef-type") || tokeniser.error("Typedef lacks a type"); + tokens.name = tokeniser.consume("identifier") || tokeniser.error("Typedef lacks a name"); + tokeniser.current = ret; + tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated typedef, expected `;`"); + return ret; + } + + get type() { + return "typedef"; + } + get name() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(this.tokens.name.value); + } + + *validate(defs) { + yield* this.idlType.validate(defs); + } +} + + +/***/ }), +/* 18 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CallbackFunction", function() { return CallbackFunction; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); + + + +class CallbackFunction extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + */ + static parse(tokeniser, base) { + const tokens = { base }; + const ret = new CallbackFunction({ source: tokeniser.source, tokens }); + tokens.name = tokeniser.consume("identifier") || tokeniser.error("Callback lacks a name"); + tokeniser.current = ret; + tokens.assign = tokeniser.consume("=") || tokeniser.error("Callback lacks an assignment"); + ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["return_type"])(tokeniser) || tokeniser.error("Callback lacks a return type"); + tokens.open = tokeniser.consume("(") || tokeniser.error("Callback lacks parentheses for arguments"); + ret.arguments = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["argument_list"])(tokeniser); + tokens.close = tokeniser.consume(")") || tokeniser.error("Unterminated callback"); + tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated callback, expected `;`"); + return ret; + } + + get type() { + return "callback"; + } + get name() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(this.tokens.name.value); + } + + *validate(defs) { + yield* this.idlType.validate(defs); + } +} + + +/***/ }), +/* 19 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Interface", function() { return Interface; }); +/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20); +/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15); +/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14); +/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(21); +/* harmony import */ var _iterable_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(22); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(5); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(3); +/* harmony import */ var _validators_interface_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(23); + + + + + + + + + +/** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ +function static_member(tokeniser) { + const special = tokeniser.consume("static"); + if (!special) return; + const member = _attribute_js__WEBPACK_IMPORTED_MODULE_1__["Attribute"].parse(tokeniser, { special }) || + _operation_js__WEBPACK_IMPORTED_MODULE_2__["Operation"].parse(tokeniser, { special }) || + tokeniser.error("No body in static member"); + return member; +} + +class Interface extends _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser, base, { partial = null } = {}) { + const tokens = { partial, base }; + return _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"].parse(tokeniser, new Interface({ source: tokeniser.source, tokens }), { + type: "interface", + inheritable: !partial, + allowedMembers: [ + [_constant_js__WEBPACK_IMPORTED_MODULE_3__["Constant"].parse], + [static_member], + [_helpers_js__WEBPACK_IMPORTED_MODULE_5__["stringifier"]], + [_iterable_js__WEBPACK_IMPORTED_MODULE_4__["IterableLike"].parse], + [_attribute_js__WEBPACK_IMPORTED_MODULE_1__["Attribute"].parse], + [_operation_js__WEBPACK_IMPORTED_MODULE_2__["Operation"].parse] + ] + }); + } + + get type() { + return "interface"; + } + + *validate(defs) { + yield* this.extAttrs.validate(defs); + if ( + !this.partial && + this.extAttrs.every(extAttr => extAttr.name !== "Exposed") && + this.extAttrs.every(extAttr => extAttr.name !== "NoInterfaceObject") + ) { + const message = `Interfaces must have \`[Exposed]\` extended attribute. \ +To fix, add, for example, \`[Exposed=Window]\`. Please also consider carefully \ +if your interface should also be exposed in a Worker scope. Refer to the \ +[WebIDL spec section on Exposed](https://heycam.github.io/webidl/#Exposed) \ +for more information.`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_6__["validationError"])(this.source, this.tokens.name, this, message); + } + + yield* super.validate(defs); + if (!this.partial) { + yield* Object(_validators_interface_js__WEBPACK_IMPORTED_MODULE_7__["checkInterfaceMemberDuplication"])(defs, this); + } + } +} + + +/***/ }), +/* 20 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Container", function() { return Container; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(11); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5); + + + + +/** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + */ +function inheritance(tokeniser) { + const colon = tokeniser.consume(":"); + if (!colon) { + return {}; + } + const inheritance = tokeniser.consume("identifier") || tokeniser.error("Inheritance lacks a type"); + return { colon, inheritance }; +} + +class Container extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + * @param {*} instance + * @param {*} args + */ + static parse(tokeniser, instance, { type, inheritable, allowedMembers }) { + const { tokens } = instance; + tokens.name = tokeniser.consume("identifier") || tokeniser.error(`Missing name in ${instance.type}`); + tokeniser.current = instance; + if (inheritable) { + Object.assign(tokens, inheritance(tokeniser)); + } + tokens.open = tokeniser.consume("{") || tokeniser.error(`Bodyless ${type}`); + instance.members = []; + while (true) { + tokens.close = tokeniser.consume("}"); + if (tokens.close) { + tokens.termination = tokeniser.consume(";") || tokeniser.error(`Missing semicolon after ${type}`); + return instance; + } + const ea = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_1__["ExtendedAttributes"].parse(tokeniser); + let mem; + for (const [parser, ...args] of allowedMembers) { + mem = parser(tokeniser, ...args); + if (mem) { + break; + } + } + if (!mem) { + tokeniser.error("Unknown member"); + } + mem.extAttrs = ea; + instance.members.push(mem); + } + } + + get partial() { + return !!this.tokens.partial; + } + get name() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["unescape"])(this.tokens.name.value); + } + get inheritance() { + if (!this.tokens.inheritance) { + return null; + } + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["unescape"])(this.tokens.inheritance.value); + } + + *validate(defs) { + for (const member of this.members) { + if (member.validate) { + yield* member.validate(defs); + } + } + } + } + + +/***/ }), +/* 21 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Constant", function() { return Constant; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _type_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(5); + + + + +class Constant extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const tokens = {}; + tokens.base = tokeniser.consume("const"); + if (!tokens.base) { + return; + } + let idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["primitive_type"])(tokeniser); + if (!idlType) { + const base = tokeniser.consume("identifier") || tokeniser.error("Const lacks a type"); + idlType = new _type_js__WEBPACK_IMPORTED_MODULE_1__["Type"]({ source: tokeniser.source, tokens: { base } }); + } + if (tokeniser.probe("?")) { + tokeniser.error("Unexpected nullable constant type"); + } + idlType.type = "const-type"; + tokens.name = tokeniser.consume("identifier") || tokeniser.error("Const lacks a name"); + tokens.assign = tokeniser.consume("=") || tokeniser.error("Const lacks value assignment"); + tokens.value = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["const_value"])(tokeniser) || tokeniser.error("Const lacks a value"); + tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated const, expected `;`"); + const ret = new Constant({ source: tokeniser.source, tokens }); + ret.idlType = idlType; + return ret; + } + + get type() { + return "const"; + } + get name() { + return unescape(this.tokens.name.value); + } + get value() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_2__["const_data"])(this.tokens.value); + } +} + + +/***/ }), +/* 22 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "IterableLike", function() { return IterableLike; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); + + + +class IterableLike extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser.js").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const start_position = tokeniser.position; + const tokens = {}; + const ret = new IterableLike({ source: tokeniser.source, tokens }); + tokens.readonly = tokeniser.consume("readonly"); + if (!tokens.readonly) { + tokens.async = tokeniser.consume("async"); + } + tokens.base = + tokens.readonly ? tokeniser.consume("maplike", "setlike") : + tokens.async ? tokeniser.consume("iterable") : + tokeniser.consume("iterable", "maplike", "setlike"); + if (!tokens.base) { + tokeniser.unconsume(start_position); + return; + } + + const { type } = ret; + const secondTypeRequired = type === "maplike" || ret.async; + const secondTypeAllowed = secondTypeRequired || type === "iterable"; + + tokens.open = tokeniser.consume("<") || tokeniser.error(`Missing less-than sign \`<\` in ${type} declaration`); + const first = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser) || tokeniser.error(`Missing a type argument in ${type} declaration`); + ret.idlType = [first]; + if (secondTypeAllowed) { + first.tokens.separator = tokeniser.consume(","); + if (first.tokens.separator) { + ret.idlType.push(Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser)); + } + else if (secondTypeRequired) { + tokeniser.error(`Missing second type argument in ${type} declaration`); + } + } + tokens.close = tokeniser.consume(">") || tokeniser.error(`Missing greater-than sign \`>\` in ${type} declaration`); + tokens.termination = tokeniser.consume(";") || tokeniser.error(`Missing semicolon after ${type} declaration`); + + return ret; + } + + get type() { + return this.tokens.base.value; + } + get readonly() { + return !!this.tokens.readonly; + } + get async() { + return !!this.tokens.async; + } +} + + +/***/ }), +/* 23 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "checkInterfaceMemberDuplication", function() { return checkInterfaceMemberDuplication; }); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3); + + +function* checkInterfaceMemberDuplication(defs, i) { + const opNames = new Set(getOperations(i).map(op => op.name)); + const partials = defs.partials.get(i.name) || []; + const mixins = defs.mixinMap.get(i.name) || []; + for (const ext of [...partials, ...mixins]) { + const additions = getOperations(ext); + yield* forEachExtension(additions, opNames, ext, i); + for (const addition of additions) { + opNames.add(addition.name); + } + } + + function* forEachExtension(additions, existings, ext, base) { + for (const addition of additions) { + const { name } = addition; + if (name && existings.has(name)) { + const message = `The operation "${name}" has already been defined for the base interface "${base.name}" either in itself or in a mixin`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_0__["validationError"])(ext.source, addition.tokens.name, ext, message); + } + } + } + + function getOperations(i) { + return i.members + .filter(({type}) => type === "operation"); + } +} + + +/***/ }), +/* 24 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Mixin", function() { return Mixin; }); +/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20); +/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(21); +/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(15); +/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(14); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5); + + + + + + +class Mixin extends _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser, base, { partial } = {}) { + const tokens = { partial, base }; + tokens.mixin = tokeniser.consume("mixin"); + if (!tokens.mixin) { + return; + } + return _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"].parse(tokeniser, new Mixin({ source: tokeniser.source, tokens }), { + type: "interface mixin", + allowedMembers: [ + [_constant_js__WEBPACK_IMPORTED_MODULE_1__["Constant"].parse], + [_helpers_js__WEBPACK_IMPORTED_MODULE_4__["stringifier"]], + [_attribute_js__WEBPACK_IMPORTED_MODULE_2__["Attribute"].parse, { noInherit: true }], + [_operation_js__WEBPACK_IMPORTED_MODULE_3__["Operation"].parse, { regular: true }] + ] + }); + } + + get type() { + return "interface mixin"; + } +} + + +/***/ }), +/* 25 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Dictionary", function() { return Dictionary; }); +/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20); +/* harmony import */ var _field_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(26); + + + +class Dictionary extends _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser, { partial } = {}) { + const tokens = { partial }; + tokens.base = tokeniser.consume("dictionary"); + if (!tokens.base) { + return; + } + return _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"].parse(tokeniser, new Dictionary({ source: tokeniser.source, tokens }), { + type: "dictionary", + inheritable: !partial, + allowedMembers: [ + [_field_js__WEBPACK_IMPORTED_MODULE_1__["Field"].parse], + ] + }); + } + + get type() { + return "dictionary"; + } +} + + +/***/ }), +/* 26 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Field", function() { return Field; }); +/* harmony import */ var _base_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(7); +/* harmony import */ var _helpers_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5); +/* harmony import */ var _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(11); +/* harmony import */ var _default_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(10); + + + + + +class Field extends _base_js__WEBPACK_IMPORTED_MODULE_0__["Base"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser) { + const tokens = {}; + const ret = new Field({ source: tokeniser.source, tokens }); + ret.extAttrs = _extended_attributes_js__WEBPACK_IMPORTED_MODULE_2__["ExtendedAttributes"].parse(tokeniser); + tokens.required = tokeniser.consume("required"); + ret.idlType = Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["type_with_extended_attributes"])(tokeniser, "dictionary-type") || tokeniser.error("Dictionary member lacks a type"); + tokens.name = tokeniser.consume("identifier") || tokeniser.error("Dictionary member lacks a name"); + ret.default = _default_js__WEBPACK_IMPORTED_MODULE_3__["Default"].parse(tokeniser); + if (tokens.required && ret.default) tokeniser.error("Required member must not have a default"); + tokens.termination = tokeniser.consume(";") || tokeniser.error("Unterminated dictionary member, expected `;`"); + return ret; + } + + get type() { + return "field"; + } + get name() { + return Object(_helpers_js__WEBPACK_IMPORTED_MODULE_1__["unescape"])(this.tokens.name.value); + } + get required() { + return !!this.tokens.required; + } + + *validate(defs) { + yield* this.idlType.validate(defs); + } +} + + +/***/ }), +/* 27 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Namespace", function() { return Namespace; }); +/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20); +/* harmony import */ var _attribute_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(15); +/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(14); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(3); + + + + + +class Namespace extends _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser, { partial } = {}) { + const tokens = { partial }; + tokens.base = tokeniser.consume("namespace"); + if (!tokens.base) { + return; + } + return _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"].parse(tokeniser, new Namespace({ source: tokeniser.source, tokens }), { + type: "namespace", + allowedMembers: [ + [_attribute_js__WEBPACK_IMPORTED_MODULE_1__["Attribute"].parse, { noInherit: true, readonly: true }], + [_operation_js__WEBPACK_IMPORTED_MODULE_2__["Operation"].parse, { regular: true }] + ] + }); + } + + get type() { + return "namespace"; + } + + *validate(defs) { + if (!this.partial && this.extAttrs.every(extAttr => extAttr.name !== "Exposed")) { + const message = `Namespaces must have [Exposed] extended attribute. \ +To fix, add, for example, [Exposed=Window]. Please also consider carefully \ +if your namespace should also be exposed in a Worker scope. Refer to the \ +[WebIDL spec section on Exposed](https://heycam.github.io/webidl/#Exposed) \ +for more information.`; + yield Object(_error_js__WEBPACK_IMPORTED_MODULE_3__["validationError"])(this.source, this.tokens.name, this, message); + } + yield* super.validate(defs); + } +} + + +/***/ }), +/* 28 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "CallbackInterface", function() { return CallbackInterface; }); +/* harmony import */ var _container_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(20); +/* harmony import */ var _operation_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(14); +/* harmony import */ var _constant_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(21); + + + + + +class CallbackInterface extends _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"] { + /** + * @param {import("../tokeniser").Tokeniser} tokeniser + */ + static parse(tokeniser, callback, { partial = null } = {}) { + const tokens = { callback }; + tokens.base = tokeniser.consume("interface"); + if (!tokens.base) { + return; + } + return _container_js__WEBPACK_IMPORTED_MODULE_0__["Container"].parse(tokeniser, new CallbackInterface({ source: tokeniser.source, tokens }), { + type: "callback interface", + inheritable: !partial, + allowedMembers: [ + [_constant_js__WEBPACK_IMPORTED_MODULE_2__["Constant"].parse], + [_operation_js__WEBPACK_IMPORTED_MODULE_1__["Operation"].parse, { regular: true }] + ] + }); + } + + get type() { + return "callback interface"; + } +} + + +/***/ }), +/* 29 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -1977,6 +2520,7 @@ return ts.definition(ts.wrap([ extended_attributes(it.extAttrs), token(it.tokens.readonly), + token(it.tokens.async), token(it.tokens.base, ts.generic), token(it.tokens.open), ts.wrap(it.idlType.map(type)), @@ -2026,17 +2570,35 @@ /***/ }), -/* 15 */ +/* 30 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "validate", function() { return validate; }); -/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6); +/* harmony import */ var _error_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3); +function getMixinMap(all, unique) { + const map = new Map(); + const includes = all.filter(def => def.type === "includes"); + for (const include of includes) { + const mixin = unique.get(include.includes); + if (!mixin) { + continue; + } + const array = map.get(include.target); + if (array) { + array.push(mixin); + } else { + map.set(include.target, [mixin]); + } + } + return map; +} + function groupDefinitions(all) { const unique = new Map(); const duplicates = new Set(); @@ -2060,7 +2622,16 @@ duplicates.add(def); } } - return { all, unique, partials, duplicates }; + return { + all, + unique, + partials, + duplicates, + mixinMap: getMixinMap(all, unique), + cache: { + typedefIncludesDictionary: new WeakMap() + }, + }; } function* checkDuplicatedNames({ unique, duplicates }) { @@ -2071,67 +2642,29 @@ } } -function* checkInterfaceMemberDuplication(defs) { - const interfaces = [...defs.unique.values()].filter(def => def.type === "interface"); - const includesMap = getIncludesMap(); - - for (const i of interfaces) { - yield* forEachInterface(i); - } - - function* forEachInterface(i) { - const opNames = new Set(getOperations(i).map(op => op.name)); - const partials = defs.partials.get(i.name) || []; - const mixins = includesMap.get(i.name) || []; - for (const ext of [...partials, ...mixins]) { - const additions = getOperations(ext); - yield* forEachExtension(additions, opNames, ext, i); - for (const addition of additions) { - opNames.add(addition.name); - } +function* validateIterable(ast) { + const defs = groupDefinitions(ast); + for (const def of defs.all) { + if (def.validate) { + yield* def.validate(defs); } } - - function* forEachExtension(additions, existings, ext, base) { - for (const addition of additions) { - const { name } = addition; - if (name && existings.has(name)) { - const message = `The operation "${name}" has already been defined for the base interface "${base.name}" either in itself or in a mixin`; - yield Object(_error_js__WEBPACK_IMPORTED_MODULE_0__["validationError"])(ext.source, addition.tokens.name, ext, message); - } - } - } - - function getOperations(i) { - return i.members - .filter(({type}) => type === "operation"); - } - - function getIncludesMap() { - const map = new Map(); - const includes = defs.all.filter(def => def.type === "includes"); - for (const include of includes) { - const array = map.get(include.target); - const mixin = defs.unique.get(include.includes); - if (!mixin) { - continue; - } - if (array) { - array.push(mixin); - } else { - map.set(include.target, [mixin]); - } - } - return map; - } + yield* checkDuplicatedNames(defs); } +// Remove this once all of our support targets expose `.flat()` by default +function flatten(array) { + if (array.flat) { + return array.flat(); + } + return [].concat(...array); +} + +/** + * @param {*} ast AST or array of ASTs + */ function validate(ast) { - const defs = groupDefinitions(ast); - return [ - ...checkDuplicatedNames(defs), - ...checkInterfaceMemberDuplication(defs) - ]; + return [...validateIterable(flatten(ast))]; }
diff --git a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js index 7b14797..3c1750f 100644 --- a/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js +++ b/third_party/blink/web_tests/external/wpt/web-animations/animation-model/animation-types/property-list.js
@@ -1305,7 +1305,7 @@ 'text-emphasis-style': { // http://dev.w3.org/csswg/css-text-decor-3/#propdef-text-emphasis-style types: [ - { type: 'discrete', options: [ [ 'filled circle', 'open dot' ] ] } + { type: 'discrete', options: [ [ 'circle', 'open dot' ] ] } ] }, 'text-indent': {
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt index 091fef8..27d7bcd 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_mediaType-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that the mediaType of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that the mediaType of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt index ec071f4f..24e47571 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_empty-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'empty'. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'empty'. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt index f0d8fa8..4764cdbb 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_json-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'json'. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'json'. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt index 9020bf9..03ac86e 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_opaque-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'opaque'. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'opaque'. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt index 57045f0..b3306b6 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_text-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'text'. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'text'. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt index 8ef2965..da38717 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_recordType_url-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'url'. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that write and read data succeed when NFCReaderOptions's recordType is set to 'url'. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt index 5a8462e..16a555a 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCReader_options_url-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that the url of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that the url of NFCReaderOptions filters relevant data sources correctly. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt index 7d4e6ec..092caee 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push.https-expected.txt
@@ -1,12 +1,12 @@ This is a testharness.js-based test. PASS Test that promise is rejected with TypeError if NDEFMessageSource is invalid. PASS 'Test that promise is rejected with SyntaxError if NDEFMessageSource contains invalid records. -FAIL NFCWriter.push should fail if abort push request before push happends. assert_throws: function "function() { throw e }" threw object "NotReadableError: No NFC adapter or cannot establish connection." that is not a DOMException AbortError: property "code" is equal to 0, expected 20 +FAIL NFCWriter.push should fail if abort push request before push happends. assert_throws: function "function() { throw e }" threw object "NotSupportedError: No NFC adapter or cannot establish connection." that is not a DOMException AbortError: property "code" is equal to 9, expected 20 PASS NFCWriter.push should fail if signal's aborted flag is set. PASS NFCWriter.push should fail if signal is not an AbortSignal. PASS NFCWriter.push should fail with TypeError when invalid timeout is provided. PASS NFCWriter.push should fail with TypeError when invalid negative timeout value is provided. -FAIL NFCWriter.push should fail with TimeoutError when timer expires. assert_throws: function "function() { throw e }" threw object "NotReadableError: No NFC adapter or cannot establish connection." that is not a DOMException TimeoutError: property "code" is equal to 0, expected 23 +FAIL NFCWriter.push should fail with TimeoutError when timer expires. assert_throws: function "function() { throw e }" threw object "NotSupportedError: No NFC adapter or cannot establish connection." that is not a DOMException TimeoutError: property "code" is equal to 9, expected 23 PASS Reject promise with NotSupportedError if NFC message size exceeds 32KB. PASS Reject promise with SyntaxError if WebNFC Id cannot be created from provided URL. PASS Reject promise with SyntaxError if 'json' record cannot be serialized.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt index ff64f61..36c13d56 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/NFCWriter_push_signal-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Synchronously signaled abort. assert_throws: function "function() { throw e }" threw object "NotReadableError: No NFC adapter or cannot establish connection." that is not a DOMException AbortError: property "code" is equal to 0, expected 20 +FAIL Synchronously signaled abort. assert_throws: function "function() { throw e }" threw object "NotSupportedError: No NFC adapter or cannot establish connection." that is not a DOMException AbortError: property "code" is equal to 9, expected 20 Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https.html b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https.html index bb2cd42..8a831b0 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https.html +++ b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_hw_disabled-manual.https.html
@@ -26,12 +26,12 @@ const readerWatcher = new EventWatcher(t, reader, ["reading", "error"]); reader.start(); const event = await readerWatcher.wait_for("error"); - assert_equals(event.error.name, 'NotReadableError'); + assert_equals(event.error.name, 'NotSupportedError'); }, "NFCReader.start should fail if NFC HW is disabled."); promise_test(t => { const writer = new NFCWriter(); - return promise_rejects(t, 'NotReadableError', writer.push(test_text_data)); + return promise_rejects(t, 'NotSupportedError', writer.push(test_text_data)); }, "NFCWriter.push should fail when NFC HW is disabled."); </script>
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt index 0377296b..25a32302 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_ArrayBuffer-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that NFCWriter.push succeeds when message is ArrayBuffer. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that NFCWriter.push succeeds when message is ArrayBuffer. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt index c4e3707..ea8b7477 100644 --- a/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt +++ b/third_party/blink/web_tests/external/wpt/web-nfc/nfc_push_DOMString-manual.https-expected.txt
@@ -1,4 +1,4 @@ This is a testharness.js-based test. -FAIL Test that NFCWriter.push succeeds when message is DOMString. promise_test: Unhandled rejection with value: object "NotReadableError: No NFC adapter or cannot establish connection." +FAIL Test that NFCWriter.push succeeds when message is DOMString. promise_test: Unhandled rejection with value: object "NotSupportedError: No NFC adapter or cannot establish connection." Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/fast/text/international/001.html b/third_party/blink/web_tests/fast/text/international/001.html index cb28d97..426df63 100644 --- a/third_party/blink/web_tests/fast/text/international/001.html +++ b/third_party/blink/web_tests/fast/text/international/001.html
@@ -3,7 +3,7 @@ <META http-equiv="Content-Type" content="text/html; charset=EUC-JP"> <TITLE>Yahoo! JAPAN </TITLE> </HEAD> -<BODY> +<BODY lang="ja-JP"> <a href="http://dir.yahoo.co.jp/Arts/Design_Arts/Architecture/">·úÃÛ</a>, <a href="http://dir.yahoo.co.jp/Arts/Museums_and_Galleries/">Èþ½Ñ´Û</a>, <a href="http://dir.yahoo.co.jp/Arts/Humanities/History/">Îò»Ë</a>,
diff --git a/third_party/blink/web_tests/fast/text/justify-ideograph-complex.html b/third_party/blink/web_tests/fast/text/justify-ideograph-complex.html index 3ab3aeb..5ca0c9e 100644 --- a/third_party/blink/web_tests/fast/text/justify-ideograph-complex.html +++ b/third_party/blink/web_tests/fast/text/justify-ideograph-complex.html
@@ -2,9 +2,11 @@ <style> p { width: 550px; text-align: justify; font-size: 12px; font-family: 'Lucida Grande'; text-rendering: optimizelegibility; } </style> +<body lang="zh-Hant-TW"> <p>【2009 年 11 月 4 日美國加州 Cupertino 訊】蘋果今天宣佈,全世界最大的應用程式商店 App Store,目前已擁有 100,000 多種來自全球開發人員的應用程式。全世界 77 個國家的 iPhone® 與 iPod touch® 用戶擁有 20 個類別的應用程式可供選擇,包括:遊戲、商用、新聞、運動、醫療、參考書籍、旅遊等等。截至目前為止,App Store 使用者下載次數已超過 20 億次,是目前全球最受歡迎的應用程式商店。 <p>蘋果全球產品行銷資深副總裁 Philip Schiller 表示:「提供 100,000 多種應用程式可供選擇的 App Store,是全世界數千萬 iPhone 和 iPod touch 使用者令人稱羨的主要原因。iPhone SDK 創造了第一個優異的行動應用程式平台,客戶也非常喜愛開發人員所創作的應用程式。」</p> <p>EA Mobile 的 Worldwide Studios 副總裁 Travis Boatman 指出:「App Store 不僅徹底改變了行動遊戲產業的生態,而且還在持續演進。有了全球 5 千多萬的 iPhone 和 iPod touch 客戶為基礎,App Store 讓我們能夠開發受到廣大的客戶喜愛的高品質 EA 遊戲。」</p> <p>Smule 的執行長 Jeff Smith 表示:「我們的 I Am T-Pain 應用程式受到全球客戶的熱烈迴響,每日超過 10,000 次的下載遠遠超越我們的預期。App Store 給了我們一個獨特的商機,讓我們開創一個非常成功的事業,相信未來將更令人期待。」</p> <p>蘋果也持續開發新的功能來提升搜尋與探索的便利性,包括:Genius for Apps、App Store Essentials、子分類清單,以及更豐富而寶貴的客戶評論。隨著新版的 iTunes® 9 推出,現在您可以輕輕鬆鬆直接在 iTunes 當中整理您的應用程式,一旦同步之後,iPhone 或 iPod touch 就會自動出現您所安排的配置。</p> <p>今年夏天推出的 iPhone OS 3.0 為 iPhone 和 iPod touch 使用者提供了 100 多種全新的功能,包括:剪貼與拷貝;MMS;新增橫向檢視的 Mail、Text 和 Notes;立體聲 Bluetooth;搖一搖就隨機播放;電視節目分級保護控制;自動登入 Wi-Fi 熱點;以及 Push Notification 服務通知等等。這些新增功能受到客戶的廣大歡迎,截至目前為止,已經有超過 20 億次的 Push Notification 服務通知發送至 App Store 應用程式。此外,最近推出的應用程式內購買機制 (In-App Purchase),為領先的應用程式開發廠商提供了一種方式讓客戶直接從應用程式當中購買內容、訂閱項目及數位服務。</p> +</body>
diff --git a/third_party/blink/web_tests/fast/text/justify-ideograph-simple.html b/third_party/blink/web_tests/fast/text/justify-ideograph-simple.html index fce166848..c23d5de 100644 --- a/third_party/blink/web_tests/fast/text/justify-ideograph-simple.html +++ b/third_party/blink/web_tests/fast/text/justify-ideograph-simple.html
@@ -2,9 +2,11 @@ <style> p { width: 550px; text-align: justify; font-size: 12px; font-family: 'Lucida Grande'; } </style> +<body lang="zh-Hant-TW"> <p>【2009 年 11 月 4 日美國加州 Cupertino 訊】蘋果今天宣佈,全世界最大的應用程式商店 App Store,目前已擁有 100,000 多種來自全球開發人員的應用程式。全世界 77 個國家的 iPhone® 與 iPod touch® 用戶擁有 20 個類別的應用程式可供選擇,包括:遊戲、商用、新聞、運動、醫療、參考書籍、旅遊等等。截至目前為止,App Store 使用者下載次數已超過 20 億次,是目前全球最受歡迎的應用程式商店。 <p>蘋果全球產品行銷資深副總裁 Philip Schiller 表示:「提供 100,000 多種應用程式可供選擇的 App Store,是全世界數千萬 iPhone 和 iPod touch 使用者令人稱羨的主要原因。iPhone SDK 創造了第一個優異的行動應用程式平台,客戶也非常喜愛開發人員所創作的應用程式。」</p> <p>EA Mobile 的 Worldwide Studios 副總裁 Travis Boatman 指出:「App Store 不僅徹底改變了行動遊戲產業的生態,而且還在持續演進。有了全球 5 千多萬的 iPhone 和 iPod touch 客戶為基礎,App Store 讓我們能夠開發受到廣大的客戶喜愛的高品質 EA 遊戲。」</p> <p>Smule 的執行長 Jeff Smith 表示:「我們的 I Am T-Pain 應用程式受到全球客戶的熱烈迴響,每日超過 10,000 次的下載遠遠超越我們的預期。App Store 給了我們一個獨特的商機,讓我們開創一個非常成功的事業,相信未來將更令人期待。」</p> <p>蘋果也持續開發新的功能來提升搜尋與探索的便利性,包括:Genius for Apps、App Store Essentials、子分類清單,以及更豐富而寶貴的客戶評論。隨著新版的 iTunes® 9 推出,現在您可以輕輕鬆鬆直接在 iTunes 當中整理您的應用程式,一旦同步之後,iPhone 或 iPod touch 就會自動出現您所安排的配置。</p> <p>今年夏天推出的 iPhone OS 3.0 為 iPhone 和 iPod touch 使用者提供了 100 多種全新的功能,包括:剪貼與拷貝;MMS;新增橫向檢視的 Mail、Text 和 Notes;立體聲 Bluetooth;搖一搖就隨機播放;電視節目分級保護控制;自動登入 Wi-Fi 熱點;以及 Push Notification 服務通知等等。這些新增功能受到客戶的廣大歡迎,截至目前為止,已經有超過 20 億次的 Push Notification 服務通知發送至 App Store 應用程式。此外,最近推出的應用程式內購買機制 (In-App Purchase),為領先的應用程式開發廠商提供了一種方式讓客戶直接從應用程式當中購買內容、訂閱項目及數位服務。</p> +</body>
diff --git a/third_party/blink/web_tests/nfc/push.html b/third_party/blink/web_tests/nfc/push.html index 72ebe4e..5201d45 100644 --- a/third_party/blink/web_tests/nfc/push.html +++ b/third_party/blink/web_tests/nfc/push.html
@@ -96,7 +96,7 @@ nfc_test(() => { mockNFC.setHWStatus(NFCHWStatus.NOT_SUPPORTED); return assertRejectsWithError(navigator.nfc.push(test_text_data), - 'NotReadableError'); + 'NotSupportedError'); }, 'nfc.push should fail when NFC HW is not supported.'); nfc_test(() => {
diff --git a/third_party/blink/web_tests/nfc/resources/nfc-helpers.js b/third_party/blink/web_tests/nfc/resources/nfc-helpers.js index c9cdc12..7d86f566 100644 --- a/third_party/blink/web_tests/nfc/resources/nfc-helpers.js +++ b/third_party/blink/web_tests/nfc/resources/nfc-helpers.js
@@ -380,7 +380,7 @@ if (this.hw_status_ === NFCHWStatus.DISABLED) return createNFCError(device.mojom.NFCErrorType.NOT_READABLE); if (this.hw_status_ === NFCHWStatus.NOT_SUPPORTED) - return createNFCError(device.mojom.NFCErrorType.NOT_READABLE); + return createNFCError(device.mojom.NFCErrorType.NOT_SUPPORTED); return null; }
diff --git a/third_party/blink/web_tests/nfc/watch.html b/third_party/blink/web_tests/nfc/watch.html index 74b1ee8..1cc85ba 100644 --- a/third_party/blink/web_tests/nfc/watch.html +++ b/third_party/blink/web_tests/nfc/watch.html
@@ -19,7 +19,7 @@ nfc_test(() => { mockNFC.setHWStatus(NFCHWStatus.NOT_SUPPORTED); - return assertRejectsWithError(navigator.nfc.watch(noop), 'NotReadableError'); + return assertRejectsWithError(navigator.nfc.watch(noop), 'NotSupportedError'); }, 'Test that nfc.watch fails if NFC hardware is not supported.') nfc_test(async () => {
diff --git a/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-complex-expected.png b/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-complex-expected.png index f3ef4888..275391e 100644 --- a/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-complex-expected.png +++ b/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-complex-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-simple-expected.png b/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-simple-expected.png index f3ef4888..275391e 100644 --- a/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-simple-expected.png +++ b/third_party/blink/web_tests/platform/linux/fast/text/justify-ideograph-simple-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-complex-expected.png b/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-complex-expected.png index 057a12c..9879ec0 100644 --- a/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-complex-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-complex-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-simple-expected.png b/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-simple-expected.png index 057a12c..9879ec0 100644 --- a/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-simple-expected.png +++ b/third_party/blink/web_tests/platform/win/fast/text/justify-ideograph-simple-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-complex-expected.png b/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-complex-expected.png index 0799e0df..7004df4 100644 --- a/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-complex-expected.png +++ b/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-complex-expected.png Binary files differ
diff --git a/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-simple-expected.png b/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-simple-expected.png index 0799e0df..7004df4 100644 --- a/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-simple-expected.png +++ b/third_party/blink/web_tests/platform/win7/fast/text/justify-ideograph-simple-expected.png Binary files differ
diff --git a/tools/grit/grit/grd_reader.py b/tools/grit/grit/grd_reader.py index 514008a3..b7bb7829 100755 --- a/tools/grit/grit/grd_reader.py +++ b/tools/grit/grit/grd_reader.py
@@ -235,4 +235,4 @@ if __name__ == '__main__': util.ChangeStdoutEncoding() - print(unicode(Parse(sys.argv[1]))) + print(six.text_type(Parse(sys.argv[1])))
diff --git a/tools/grit/grit/grd_reader_unittest.py b/tools/grit/grit/grd_reader_unittest.py index cebcf103..920a92f 100755 --- a/tools/grit/grit/grd_reader_unittest.py +++ b/tools/grit/grit/grd_reader_unittest.py
@@ -14,6 +14,7 @@ import unittest +import six from six import StringIO from grit import exception @@ -55,7 +56,7 @@ </grit>''' pseudo_file = StringIO(input) tree = grd_reader.Parse(pseudo_file, '.') - output = unicode(tree) + output = six.text_type(tree) expected_output = input.replace(u' base_dir="."', u'') self.assertEqual(expected_output, output) self.failUnless(tree.GetNodeById('IDS_GREETING'))
diff --git a/tools/grit/grit/node/base.py b/tools/grit/grit/node/base.py index 5159c5e..04d1f01 100644 --- a/tools/grit/grit/node/base.py +++ b/tools/grit/grit/node/base.py
@@ -60,7 +60,7 @@ def __exit__(self, exc_type, exc_value, traceback): if exc_type is not None: - print(u'Error processing node %s' % unicode(self)) + print(u'Error processing node %s' % six.text_type(self)) def __iter__(self): '''A preorder iteration through the tree that this node is the root of.'''
diff --git a/tools/grit/grit/node/misc.py b/tools/grit/grit/node/misc.py index 36ce8ac0..3631750 100644 --- a/tools/grit/grit/node/misc.py +++ b/tools/grit/grit/node/misc.py
@@ -11,6 +11,8 @@ import re import sys +import six + from grit import constants from grit import exception from grit import util @@ -577,7 +579,7 @@ assert self._id_map is None, 'AssignFirstIds() after InitializeIds()' # If the input is a stream, then we're probably in a unit test and # should skip this step. - if type(filename_or_stream) not in (str, unicode): + if not isinstance(filename_or_stream, six.string_types): return # Nothing to do if the first_ids_filename attribute isn't set.
diff --git a/tools/grit/grit/tool/android2grd.py b/tools/grit/grit/tool/android2grd.py index 7c88176..afb61c4 100644 --- a/tools/grit/grit/tool/android2grd.py +++ b/tools/grit/grit/tool/android2grd.py
@@ -12,6 +12,7 @@ from xml.dom import Node import xml.dom.minidom +import six from six import StringIO import grit.node.empty @@ -175,7 +176,7 @@ # Do the hard work -- convert the Android dom to grd file contents. grd_dom = self.AndroidDomToGrdDom(android_dom) - grd_string = unicode(grd_dom) + grd_string = six.text_type(grd_dom) # Write the grd string to a file in grd_dir. grd_filename = self.name + '.grd'
diff --git a/tools/grit/grit/tool/rc2grd.py b/tools/grit/grit/tool/rc2grd.py index dc406aaa..57fb682 100644 --- a/tools/grit/grit/tool/rc2grd.py +++ b/tools/grit/grit/tool/rc2grd.py
@@ -201,7 +201,7 @@ os.path.splitext(os.path.basename(path))[0] + '.grd') rctext = util.ReadFile(path, self.input_encoding) - grd_text = unicode(self.Process(rctext, path)) + grd_text = six.text_type(self.Process(rctext, path)) with util.WrapOutputStream(file(out_path, 'w'), 'utf-8') as outfile: outfile.write(grd_text)
diff --git a/tools/grit/grit/tool/xmb.py b/tools/grit/grit/tool/xmb.py index bfce9607..454bdb25 100644 --- a/tools/grit/grit/tool/xmb.py +++ b/tools/grit/grit/tool/xmb.py
@@ -13,6 +13,8 @@ from xml.sax import saxutils +import six + from grit import grd_reader from grit import lazy_re from grit import tclib @@ -36,9 +38,7 @@ internal Translation Console tool. May be used for attributes as well as for contents. """ - if not type(s) == unicode: - s = unicode(s) - return saxutils.escape(s, _XML_QUOTE_ESCAPES).encode('utf-8') + return saxutils.escape(six.text_type(s), _XML_QUOTE_ESCAPES).encode('utf-8') def _WriteAttribute(file, name, value): @@ -55,7 +55,7 @@ def _WriteMessage(file, message): presentable_content = message.GetPresentableContent() - assert (type(presentable_content) == unicode or + assert (isinstance(presentable_content, six.string_types) or (len(message.parts) == 1 and type(message.parts[0] == tclib.Placeholder))) preserve_space = presentable_content != _WHITESPACES_REGEX.sub(
diff --git a/tools/grit/grit/util.py b/tools/grit/grit/util.py index ffdc0ec8..4a7194b 100644 --- a/tools/grit/grit/util.py +++ b/tools/grit/grit/util.py
@@ -15,6 +15,7 @@ import tempfile from xml.sax import saxutils +import six from six import StringIO from six.moves import html_entities as entities @@ -329,7 +330,7 @@ base_dir: The base_dir attribute of the <grit> tag. ''' from grit import grd_reader - if isinstance(body, unicode): + if isinstance(body, six.text_type): body = body.encode('utf-8') if base_dir is None: base_dir = PathFromRoot('.')
diff --git a/tools/grit/pak_util.py b/tools/grit/pak_util.py index dfa7e18..b5c75c4c 100755 --- a/tools/grit/pak_util.py +++ b/tools/grit/pak_util.py
@@ -16,6 +16,8 @@ import os import sys +import six + from grit.format import data_pack @@ -74,7 +76,7 @@ desc = '<data>' if try_decode: try: - desc = unicode(data, encoding) + desc = six.text_type(data, encoding) if len(desc) > 60: desc = desc[:60] + u'...' desc = desc.replace('\n', '\\n')
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index 6dd7379..4e871fed 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -242,20 +242,6 @@ 'ios-device-goma-canary-clobber': 'ios_error', 'ios-device-goma-latest-clobber': 'ios_error', - # TODO(yyanagisawa): remove when rename finishes. - 'Linux x64 Goma Canary (clobber)': 'release_bot', - 'Linux x64 Goma Canary LocalOutputCache': 'release_bot', - 'Linux x64 Goma Latest Client (clobber)': 'release_bot', - 'Linux x64 Goma Latest Client LocalOutputCache': 'release_bot', - 'Win Goma Canary LocalOutputCache': 'release_bot_x86_minimal_symbols_enable_archive_compression', - 'Win Goma Latest Client LocalOutputCache': 'release_bot_x86_minimal_symbols_enable_archive_compression', - 'Mac Goma Canary (clobber)': 'release_bot_mac_strip_minimal_symbols', - 'Mac Goma Latest Client (clobber)': 'release_bot_mac_strip_minimal_symbols', - 'Mac Goma Canary LocalOutputCache': 'release_bot_mac_strip_minimal_symbols', - 'Mac Goma Latest Client LocalOutputCache': 'release_bot_mac_strip_minimal_symbols', - 'Android Builder (dbg) Goma Canary': 'android_without_codecs_debug_bot', - 'Android Builder (dbg) Goma Latest Client': 'android_without_codecs_debug_bot', - # TODO(yyanagisawa): deprecate cl.exe. 'Win cl.exe Goma Canary LocalOutputCache': 'release_bot_x86_minimal_symbols_enable_archive_compression_no_clang', 'Win cl.exe Goma Latest Client LocalOutputCache': 'release_bot_x86_minimal_symbols_enable_archive_compression_no_clang', @@ -548,12 +534,12 @@ 'V8 Android GN (dbg)': 'android_debug_bot', 'V8 Blink Linux': 'release_bot', 'V8 Blink Linux Debug': 'release_bot_v8_debug', + 'V8 Blink Linux Future': 'release_bot', 'V8 Blink Linux Layout NG': 'release_bot', 'V8 Blink Mac': 'release_bot', 'V8 Blink Win': 'release_bot', 'V8 Linux GN': 'release_bot', 'V8-Blink Linux 64': 'release_bot', - 'V8-Blink Linux 64 - future': 'release_bot', 'V8-Blink Linux 64 (dbg)': 'release_bot_v8_debug', 'V8-Blink Mac': 'release_bot', 'V8-Blink Win': 'release_bot_x86_minimal_symbols', @@ -633,7 +619,7 @@ # TODO(crbug/597596): Switch this back to debug_trybot when cronet's # shared library loading is fixed. 'android-cronet-arm-dbg': 'android_cronet_debug_static_bot_arm_no_neon', - 'android-kitkat-arm-coverage-dbg': 'android_debug_static_trybot_java_coverage', + 'android-kitkat-arm-coverage-rel': 'android_release_trybot_java_coverage', 'android-kitkat-arm-rel': 'android_release_trybot', 'android-marshmallow-arm64-rel': 'gpu_tests_android_release_trybot_arm64_resource_whitelisting', 'android-oreo-arm64-cts-networkservice-dbg': 'android_debug_trybot_arm64', @@ -1035,10 +1021,6 @@ 'android', 'debug_static_bot', 'x86', ], - 'android_debug_static_trybot_java_coverage': [ - 'android', 'debug_static_trybot', 'strip_debug_info', 'java_coverage', - ], - 'android_debug_trybot': [ 'android', 'debug_trybot', ], @@ -1112,6 +1094,10 @@ 'webview_google', ], + 'android_release_trybot_java_coverage': [ + 'android', 'release_trybot', 'strip_debug_info', 'java_coverage', + ], + 'android_release_trybot_x86': [ 'android', 'release_trybot', 'strip_debug_info', 'x86', ], @@ -2111,10 +2097,6 @@ 'mixins': ['debug', 'static', 'minimal_symbols', 'goma'], }, - 'debug_static_trybot': { - 'mixins': ['debug_static_bot'], - }, - 'debug_trybot': { 'mixins': ['debug_bot'], },
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index af303f4..7a66eea 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -19762,8 +19762,8 @@ <int value="871" label="DELETED_FILESYSTEM_UNOBSERVEENTRY"/> <int value="872" label="DELETED_FILESYSTEM_GETOBSERVEDENTRIES"/> <int value="873" label="BROWSINGDATA_REMOVESERVICEWORKERS"/> - <int value="874" label="USBPRIVATE_GETDEVICES"/> - <int value="875" label="USBPRIVATE_GETDEVICEINFO"/> + <int value="874" label="DELETED_USBPRIVATE_GETDEVICES"/> + <int value="875" label="DELETED_USBPRIVATE_GETDEVICEINFO"/> <int value="876" label="DELETED_EASYUNLOCKPRIVATE_UPDATESCREENLOCKSTATE"/> <int value="877" label="CAST_CHANNEL_GETLOGS"/> <int value="878" label="DELETED_EASYUNLOCKPRIVATE_SETPERMITACCESS"/> @@ -24302,6 +24302,10 @@ <int value="2995" label="CSSValueOverflowOverlay"/> <int value="2996" label="RequestedFileSystemTemporary"/> <int value="2997" label="RequestedFileSystemPersistent"/> + <int value="2998" + label="ElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTop"/> + <int value="2999" + label="ElementWithLeftwardOrUpwardOverflowDirection_ScrollLeftOrTopSetPositive"/> </enum> <enum name="FeaturePolicyAllowlistType"> @@ -35025,6 +35029,7 @@ label="OmniboxSpeculativeServiceWorkerStartOnQueryInput:disabled"/> <int value="-990187062" label="SendTabToSelfShowSendingUI:enabled"/> <int value="-989671895" label="OfflineIndicatorAlwaysHttpProbe:enabled"/> + <int value="-987470173" label="ClickToCallOpenDialerDirectly:disabled"/> <int value="-984052166" label="DoodlesOnLocalNtp:enabled"/> <int value="-981237342" label="SyncUSSAutofillWalletMetadata:disabled"/> <int value="-980260493" label="NTPSnippets:disabled"/> @@ -35851,6 +35856,7 @@ <int value="181150000" label="CrosVmCupsProxy:enabled"/> <int value="183208826" label="TabGroups:enabled"/> <int value="185991204" label="enable-webrtc-srtp-encrypted-headers"/> + <int value="186463628" label="DnsOverHttps:disabled"/> <int value="188610022" label="NewMessageListView:enabled"/> <int value="189728101" label="FasterLocationReload:disabled"/> <int value="189777537" label="DisableInitialMostVisitedFadeIn:enabled"/> @@ -36227,6 +36233,7 @@ <int value="724208771" label="TabsInCBD:enabled"/> <int value="724427456" label="WebAuthenticationPINSupport:disabled"/> <int value="725270017" label="ScrollAnchorSerialization:disabled"/> + <int value="725870294" label="RequestUnbufferedDispatch:disabled"/> <int value="726764779" label="WebXRGamepadSupport:enabled"/> <int value="727270087" label="PromosOnLocalNtp:enabled"/> <int value="727571565" label="PasswordForceSaving"/> @@ -36934,6 +36941,7 @@ <int value="1739456903" label="PWAFullCodeCache:enabled"/> <int value="1742398600" label="OmniboxUIExperimentBoldUserTextOnSearchSuggestions:enabled"/> + <int value="1745053254" label="ClickToCallOpenDialerDirectly:enabled"/> <int value="1747279677" label="disable-delegated-renderer"/> <int value="1748481830" label="AppManagement:enabled"/> <int value="1750822869" label="CrostiniBackup:disabled"/> @@ -36977,6 +36985,7 @@ <int value="1810311887" label="WebAssemblyThreads:enabled"/> <int value="1812368073" label="enable-new-app-list-mixer"/> <int value="1814671708" label="disable-password-manager-reauthentication"/> + <int value="1816174635" label="RequestUnbufferedDispatch:enabled"/> <int value="1816843861" label="ServiceWorkerServicification:enabled"/> <int value="1817312143" label="num-raster-threads"/> <int value="1818829958" label="IdentityDisc:enabled"/> @@ -37159,6 +37168,7 @@ <int value="2037756154" label="enable-impl-side-painting"/> <int value="2039276757" label="EnableOverviewRoundedCorners:enabled"/> <int value="2040316611" label="IPH_ReopenTab:enabled"/> + <int value="2043141918" label="DnsOverHttps:enabled"/> <int value="2043321329" label="OfflinePagesPrefetchingUI:disabled"/> <int value="2047695652" label="DelegateOverscrollSwipes:enabled"/> <int value="2047981703" label="IntentPicker:enabled"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 05a38d21..97f8e308 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -45094,7 +45094,7 @@ </histogram> <histogram name="FileBrowser.ImportController.DeviceYanked" enum="Boolean" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Whether an external media device was removed during the @@ -45103,7 +45103,7 @@ </histogram> <histogram name="FileBrowser.ImportController.ImportCancelled" - enum="BooleanCanceled" expires_after="M79"> + enum="BooleanCanceled" expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Whether the media import process was cancelled. @@ -45130,7 +45130,7 @@ </summary> </histogram> -<histogram name="FileBrowser.Load" units="ms" expires_after="M79"> +<histogram name="FileBrowser.Load" units="ms" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45142,7 +45142,7 @@ </histogram> <histogram name="FileBrowser.Location.OnEntryExpandedOrCollapsed.NonTopLevel" - enum="FileManagerRootType" expires_after="M79"> + enum="FileManagerRootType" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45153,7 +45153,7 @@ </histogram> <histogram name="FileBrowser.Location.OnEntryExpandedOrCollapsed.TopLevel" - enum="FileManagerRootType" expires_after="M79"> + enum="FileManagerRootType" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45184,7 +45184,7 @@ </histogram> <histogram name="FileBrowser.MediaImport.Cancelled" enum="BooleanCanceled" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Whether the media import (Photos/Video) from external @@ -45193,7 +45193,7 @@ </histogram> <histogram name="FileBrowser.MediaImport.Duplicates" units="count" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Count of duplicate media (Photos/Videos) files that @@ -45202,7 +45202,7 @@ </histogram> <histogram name="FileBrowser.MediaImport.ErrorCount" units="count" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Number of errors that occured during an upload session. @@ -45210,7 +45210,7 @@ </histogram> <histogram name="FileBrowser.MediaImport.ImportCount" units="count" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Count of individual media (Photos/Videos) uploaded from @@ -45219,7 +45219,7 @@ </histogram> <histogram name="FileBrowser.MediaImport.ImportMB" units="MBytes" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Size of the media (Photos/Videos) uploaded from a @@ -45228,7 +45228,7 @@ </histogram> <histogram name="FileBrowser.MediaImport.Started" enum="BooleanAttempted" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <summary> Chrome OS Files App: Whether the media import (Photos/Video) from external @@ -45453,7 +45453,7 @@ </histogram> <histogram name="FileBrowser.Recent.LoadArcMedia" units="ms" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45463,7 +45463,7 @@ </histogram> <histogram name="FileBrowser.Recent.LoadCrostini" units="ms" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45473,7 +45473,7 @@ </histogram> <histogram name="FileBrowser.Recent.LoadDownloads" units="ms" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45482,7 +45482,7 @@ </summary> </histogram> -<histogram name="FileBrowser.Recent.LoadDrive" units="ms" expires_after="M79"> +<histogram name="FileBrowser.Recent.LoadDrive" units="ms" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45491,7 +45491,7 @@ </summary> </histogram> -<histogram name="FileBrowser.Recent.LoadTotal" units="ms" expires_after="M79"> +<histogram name="FileBrowser.Recent.LoadTotal" units="ms" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45563,7 +45563,7 @@ </histogram> <histogram name="FileBrowser.ViewingFileType" enum="ViewFileType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45573,7 +45573,7 @@ </histogram> <histogram name="FileBrowser.ViewingFileType.Offline" enum="ViewFileType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45584,7 +45584,7 @@ </histogram> <histogram name="FileBrowser.ViewingFileType.Online" enum="ViewFileType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45595,7 +45595,7 @@ </histogram> <histogram name="FileBrowser.ViewingRootType" enum="FileManagerRootType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45605,7 +45605,7 @@ </histogram> <histogram name="FileBrowser.ViewingRootType.Offline" - enum="FileManagerRootType" expires_after="M79"> + enum="FileManagerRootType" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45616,7 +45616,7 @@ </histogram> <histogram name="FileBrowser.ViewingRootType.Online" enum="FileManagerRootType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45627,7 +45627,7 @@ </histogram> <histogram name="FileBrowser.ViewingTaskType" enum="FileManagerTaskType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45637,7 +45637,7 @@ </histogram> <histogram name="FileBrowser.ViewingTaskType.Offline" - enum="FileManagerTaskType" expires_after="M79"> + enum="FileManagerTaskType" expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45648,7 +45648,7 @@ </histogram> <histogram name="FileBrowser.ViewingTaskType.Online" enum="FileManagerTaskType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -45659,7 +45659,7 @@ </histogram> <histogram name="FileBrowser.VolumeType" enum="FileManagerVolumeType" - expires_after="M79"> + expires_after="M88"> <owner>slangley@chromium.org</owner> <owner>weifangsun@chromium.org</owner> <summary> @@ -48936,6 +48936,17 @@ </summary> </histogram> +<histogram name="GPU.SharedImage.ContentConsumed" enum="BooleanMatched" + expires_after="2020-08-12"> + <owner>penghuang@chromium.org</owner> + <owner>backer@chromium.org</owner> + <summary> + Whether or not the content of a SharedImage is consumed. False indicates the + content of a SharedImage is never used due to destroying the SharedImage or + writing new content to it before using it. + </summary> +</histogram> + <histogram name="GPU.SoftwareRendererLifetimeEvents" enum="GPUProcessLifetimeEvent" expires_after="2018-06-05"> <obsolete> @@ -90197,8 +90208,8 @@ <owner>chrome-privacy-core@google.com</owner> <summary> This histogram records the number of searches done from omnibox using - default search engine on desktop, sliced based on being in regular mode or - private modes. + default search engine on desktop and android devices, sliced based on being + in regular mode or private modes. </summary> </histogram>
diff --git a/ui/accessibility/ax_node_position_unittest.cc b/ui/accessibility/ax_node_position_unittest.cc index 8f00c18..69da285 100644 --- a/ui/accessibility/ax_node_position_unittest.cc +++ b/ui/accessibility/ax_node_position_unittest.cc
@@ -20,6 +20,7 @@ #include "ui/accessibility/ax_node_position.h" #include "ui/accessibility/ax_range.h" #include "ui/accessibility/ax_serializable_tree.h" +#include "ui/accessibility/ax_text_boundary.h" #include "ui/accessibility/ax_tree_serializer.h" #include "ui/accessibility/ax_tree_update.h" @@ -158,41 +159,96 @@ DISALLOW_COPY_AND_ASSIGN(AXPositionTest); }; -// Used by parameterized tests. -// The test starts from a pre-determined position and repeats until there are no -// more expectations. -// TODO(nektar): Only text positions are tested for now. -struct TestParam { - TestParam() = default; +// Used by AXPositionCreatePositionAtTextBoundaryTestWithParam. +// +// Every test instance starts from a pre-determined position and calls the +// CreatePositionAtTextBoundary method with the arguments provided in this +// struct. +struct CreatePositionAtTextBoundaryTestParam { + CreatePositionAtTextBoundaryTestParam() = default; // Required by GTest framework. - TestParam(const TestParam& other) = default; - TestParam& operator=(const TestParam& other) = default; + CreatePositionAtTextBoundaryTestParam( + const CreatePositionAtTextBoundaryTestParam& other) = default; + CreatePositionAtTextBoundaryTestParam& operator=( + const CreatePositionAtTextBoundaryTestParam& other) = default; - ~TestParam() = default; + ~CreatePositionAtTextBoundaryTestParam() = default; + + // The text boundary to move to. + AXTextBoundary boundary; + + // The direction to move to. + AXTextBoundaryDirection direction; + + // What to do when the starting position is already at a text boundary, or + // when the movement operation will cause us to cross the starting object's + // boundary. + AXBoundaryBehavior boundary_behavior; + + // The text position that should be returned, if the method was called on a + // text position instance. + std::string expected_text_position; +}; + +// This is a fixture for a set of parameterized tests that test the +// |CreatePositionAtTextBoundary| method with all possible input arguments. +class AXPositionCreatePositionAtTextBoundaryTestWithParam + : public AXPositionTest, + public testing::WithParamInterface< + CreatePositionAtTextBoundaryTestParam> { + public: + AXPositionCreatePositionAtTextBoundaryTestWithParam() = default; + ~AXPositionCreatePositionAtTextBoundaryTestWithParam() override = default; + + DISALLOW_COPY_AND_ASSIGN(AXPositionCreatePositionAtTextBoundaryTestWithParam); +}; + +// Used by |AXPositionTextNavigationTestWithParam|. +// +// The test starts from a pre-determined position and repeats a text navigation +// operation, such as |CreateNextWordStartPosition|, until it runs out of +// expectations. +struct TextNavigationTestParam { + TextNavigationTestParam() = default; + + // Required by GTest framework. + TextNavigationTestParam(const TextNavigationTestParam& other) = default; + TextNavigationTestParam& operator=(const TextNavigationTestParam& other) = + default; + + ~TextNavigationTestParam() = default; // Stores the method that should be called repeatedly by the test to create // the next position. base::RepeatingCallback<TestPositionType(const TestPositionType&)> TestMethod; // The node at which the test should start. - int32_t start_node_id_; + AXNode::AXID start_node_id; // The text offset at which the test should start. - int start_offset_; + int start_offset; // A list of positions that should be returned from the method being tested, // in stringified form. std::vector<std::string> expectations; }; -class AXPositionTestWithParam : public AXPositionTest, - public testing::WithParamInterface<TestParam> { +// This is a fixture for a set of parameterized tests that ensure that text +// navigation operations, such as |CreateNextWordStartPosition|, work properly. +// +// Starting from a given position, test instances call a given text navigation +// method repeatedly and compare the return values to a set of expectations. +// +// TODO(nektar): Only text positions are tested for now. +class AXPositionTextNavigationTestWithParam + : public AXPositionTest, + public testing::WithParamInterface<TextNavigationTestParam> { public: - AXPositionTestWithParam() = default; - ~AXPositionTestWithParam() override = default; + AXPositionTextNavigationTestWithParam() = default; + ~AXPositionTextNavigationTestWithParam() override = default; - DISALLOW_COPY_AND_ASSIGN(AXPositionTestWithParam); + DISALLOW_COPY_AND_ASSIGN(AXPositionTextNavigationTestWithParam); }; const char* AXPositionTest::TEXT_VALUE = "Line 1\nLine 2"; @@ -3850,9 +3906,22 @@ // Parameterized tests. // -TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityDownstream) { +TEST_P(AXPositionCreatePositionAtTextBoundaryTestWithParam, + TextPositionBeforeStaticText) { TestPositionType text_position = AXNodePosition::CreateTextPosition( - tree_.data().tree_id, GetParam().start_node_id_, GetParam().start_offset_, + tree_.data().tree_id, static_text2_.id, 0 /* text_offset */, + ax::mojom::TextAffinity::kDownstream); + ASSERT_TRUE(text_position->IsTextPosition()); + text_position = text_position->CreatePositionAtTextBoundary( + GetParam().boundary, GetParam().direction, GetParam().boundary_behavior); + EXPECT_NE(nullptr, text_position); + EXPECT_EQ(GetParam().expected_text_position, text_position->ToString()); +} + +TEST_P(AXPositionTextNavigationTestWithParam, + TraverseTreeStartingWithAffinityDownstream) { + TestPositionType text_position = AXNodePosition::CreateTextPosition( + tree_.data().tree_id, GetParam().start_node_id, GetParam().start_offset, ax::mojom::TextAffinity::kDownstream); ASSERT_TRUE(text_position->IsTextPosition()); for (const std::string& expectation : GetParam().expectations) { @@ -3862,9 +3931,10 @@ } } -TEST_P(AXPositionTestWithParam, TraverseTreeStartingWithAffinityUpstream) { +TEST_P(AXPositionTextNavigationTestWithParam, + TraverseTreeStartingWithAffinityUpstream) { TestPositionType text_position = AXNodePosition::CreateTextPosition( - tree_.data().tree_id, GetParam().start_node_id_, GetParam().start_offset_, + tree_.data().tree_id, GetParam().start_node_id, GetParam().start_offset, ax::mojom::TextAffinity::kUpstream); ASSERT_TRUE(text_position->IsTextPosition()); for (const std::string& expectation : GetParam().expectations) { @@ -3878,1867 +3948,2165 @@ // Instantiations of parameterized tests. // +// Only test with AXBoundaryBehavior::CrossBoundary for now. +INSTANTIATE_TEST_SUITE_P( + CreatePositionAtTextBoundary, + AXPositionCreatePositionAtTextBoundaryTestWithParam, + testing::Values( + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kCharacter, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=9 text_offset=5 affinity=downstream " + "annotated_text=Line <2>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kCharacter, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=1 affinity=downstream " + "annotated_text=L<i>ne 2"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kFormatChange, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=7 text_offset=0 affinity=downstream " + "annotated_text=<\n>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kFormatChange, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=9 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kLineEnd, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=6 affinity=downstream " + "annotated_text=Line 1<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kLineEnd, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kLineStart, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=0 affinity=downstream " + "annotated_text=<L>ine 1"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kLineStart, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kLineStartOrEnd, + AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=0 affinity=downstream " + "annotated_text=<L>ine 1"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kLineStartOrEnd, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kObject, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=0 affinity=downstream " + "annotated_text=<L>ine 2"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kObject, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kParagraphEnd, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=3 text_offset=0 affinity=downstream " + "annotated_text=<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kParagraphEnd, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kParagraphStart, + AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=0 affinity=downstream " + "annotated_text=<L>ine 1"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kParagraphStart, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, "NullPosition"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kParagraphStartOrEnd, + AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=0 affinity=downstream " + "annotated_text=<L>ine 1"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kParagraphStartOrEnd, + AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + // TODO(accessibility): Add tests for sentence boundary. + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWebPage, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=1 text_offset=0 affinity=downstream " + "annotated_text=<L>ine 1\nLine 2"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWebPage, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=9 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWordEnd, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=6 affinity=downstream " + "annotated_text=Line 1<>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWordEnd, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=4 affinity=downstream " + "annotated_text=Line< >2"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWordStart, AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=5 affinity=downstream " + "annotated_text=Line <1>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWordStart, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=5 affinity=downstream " + "annotated_text=Line <2>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWordStartOrEnd, + AXTextBoundaryDirection::kBackwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=6 text_offset=5 affinity=downstream " + "annotated_text=Line <1>"}, + CreatePositionAtTextBoundaryTestParam{ + AXTextBoundary::kWordStartOrEnd, AXTextBoundaryDirection::kForwards, + AXBoundaryBehavior::CrossBoundary, + "TextPosition anchor_id=8 text_offset=4 affinity=downstream " + "annotated_text=Line< >2"})); + INSTANTIATE_TEST_SUITE_P( CreateNextWordStartPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=5 " - "affinity=downstream annotated_text=Line <1>", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=5 " - "affinity=downstream annotated_text=Line <2>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=5 " - "affinity=downstream annotated_text=Line <2>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=5 " + "affinity=downstream annotated_text=Line <1>", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=5 " + "affinity=downstream annotated_text=Line <2>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=5 " + "affinity=downstream annotated_text=Line <2>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreateNextWordStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=5 " - "affinity=downstream annotated_text=Line <1>", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=5 " - "affinity=downstream annotated_text=Line <2>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=5 " + "affinity=downstream annotated_text=Line <1>", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=5 " + "affinity=downstream annotated_text=Line <2>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextWordStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=5 " - "affinity=downstream annotated_text=Line <1>", - "TextPosition anchor_id=5 text_offset=5 " - "affinity=downstream annotated_text=Line <1>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=5 " - "affinity=downstream annotated_text=Line <2>", - "TextPosition anchor_id=9 text_offset=5 " - "affinity=downstream annotated_text=Line <2>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=5 " + "affinity=downstream annotated_text=Line <1>", + "TextPosition anchor_id=5 text_offset=5 " + "affinity=downstream annotated_text=Line <1>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=5 " + "affinity=downstream annotated_text=Line <2>", + "TextPosition anchor_id=9 text_offset=5 " + "affinity=downstream annotated_text=Line <2>"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousWordStartPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=6 text_offset=5 " - "affinity=downstream annotated_text=Line <1>", - "TextPosition anchor_id=6 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=6 text_offset=5 " + "affinity=downstream annotated_text=Line <1>", + "TextPosition anchor_id=6 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousWordStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=5 " - "affinity=downstream annotated_text=Line <1>\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=5 " + "affinity=downstream annotated_text=Line <1>\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousWordStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=1 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>", - "TextPosition anchor_id=4 text_offset=12 " - "affinity=downstream annotated_text=Line 1\nLine <2>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=5 " - "affinity=downstream annotated_text=Line <1>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=1 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>", + "TextPosition anchor_id=4 text_offset=12 " + "affinity=downstream annotated_text=Line 1\nLine <2>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=5 " + "affinity=downstream annotated_text=Line <1>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreateNextWordEndPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=9 text_offset=4 " - "affinity=downstream annotated_text=Line< >2", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=9 text_offset=4 " + "affinity=downstream annotated_text=Line< >2", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreateNextWordEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextWordEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=1 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=4 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=4 " - "affinity=downstream annotated_text=Line< >2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=1 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=4 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=4 " + "affinity=downstream annotated_text=Line< >2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousWordEndPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=6 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=6 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=6 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=6 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousWordEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - { - "TextPosition anchor_id=1 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - }}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=11 " - "affinity=downstream annotated_text=Line 1\nLine< >2", - "TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=4 " - "affinity=downstream annotated_text=Line< >1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + { + "TextPosition anchor_id=1 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + }}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=11 " + "affinity=downstream annotated_text=Line 1\nLine< >2", + "TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=4 " + "affinity=downstream annotated_text=Line< >1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousWordEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1", - "TextPosition anchor_id=5 text_offset=4 " - "affinity=downstream annotated_text=Line< >1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousWordEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=4 " - "affinity=downstream annotated_text=Line< >2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1", + "TextPosition anchor_id=5 text_offset=4 " + "affinity=downstream annotated_text=Line< >1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousWordEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=4 " + "affinity=downstream annotated_text=Line< >2"}})); INSTANTIATE_TEST_SUITE_P( CreateNextLineStartPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreateNextLineStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextLineStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 affinity=downstream " - "annotated_text=Line 2<>", - "TextPosition anchor_id=9 text_offset=6 affinity=downstream " - "annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>", + "TextPosition anchor_id=9 text_offset=6 affinity=downstream " + "annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousLineStartPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 13 /* text_offset at the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=6 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 13 /* text_offset at the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=6 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousLineStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 13 /* text_offset at the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 13 /* text_offset at the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousLineStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 13 /* text_offset at the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 13 /* text_offset at the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreateNextLineEndPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreateNextLineEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextLineEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousLineEndPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=2 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=2 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=2 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=2 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=2 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=2 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=2 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=2 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousLineEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( // Note that for the first two tests we can't go past the line ending at // "Line 1" to test for "NullPosition'", because the text position at // the beginning of the soft line break is equivalent to the position at // the end of the line's text and so an infinite recursion will occur. - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousLineEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 12 /* text_offset one before the end of root. */, - {"TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=1 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 12 /* text_offset one before the end of text field */, - {"TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2", - "TextPosition anchor_id=4 text_offset=6 " - "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX1_ID, - 2 /* text_offset */, - {"TextPosition anchor_id=6 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "TextPosition anchor_id=6 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousLineEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=6 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 12 /* text_offset one before the end of root. */, + {"TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=1 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 12 /* text_offset one before the end of text field */, + {"TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2", + "TextPosition anchor_id=4 text_offset=6 " + "affinity=downstream annotated_text=Line 1<\n>Line 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX1_ID, + 2 /* text_offset */, + {"TextPosition anchor_id=6 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "TextPosition anchor_id=6 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousLineEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=6 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextParagraphStartPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreateNextParagraphStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextParagraphStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousParagraphStartPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 13 /* text_offset at the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=6 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 13 /* text_offset at the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=6 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousParagraphStartPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 13 /* text_offset at the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 13 /* text_offset at the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousParagraphStartPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 13 /* text_offset at the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 5 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1", - "TextPosition anchor_id=5 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphStartPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 13 /* text_offset at the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=downstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 5 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1", + "TextPosition anchor_id=5 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphStartPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreateNextParagraphEndPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreateNextParagraphEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "TextPosition anchor_id=1 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>", - "TextPosition anchor_id=4 text_offset=13 " - "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>", - "TextPosition anchor_id=5 text_offset=6 " - "affinity=downstream annotated_text=Line 1<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "TextPosition anchor_id=1 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>", + "TextPosition anchor_id=4 text_offset=13 " + "affinity=downstream annotated_text=Line 1\nLine 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>", + "TextPosition anchor_id=5 text_offset=6 " + "affinity=downstream annotated_text=Line 1<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}})); INSTANTIATE_TEST_SUITE_P( CreateNextParagraphEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - STATIC_TEXT1_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>", - "TextPosition anchor_id=9 text_offset=6 " - "affinity=downstream annotated_text=Line 2<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - LINE_BREAK_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreateNextParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - LINE_BREAK_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + STATIC_TEXT1_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>", + "TextPosition anchor_id=9 text_offset=6 " + "affinity=downstream annotated_text=Line 2<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + LINE_BREAK_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreateNextParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + LINE_BREAK_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousParagraphEndPositionWithBoundaryBehaviorCrossBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - ROOT_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - TEXT_FIELD_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::CrossBoundary); - }), - INLINE_BOX2_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>", - "NullPosition"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + ROOT_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + TEXT_FIELD_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::CrossBoundary); + }), + INLINE_BOX2_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>", + "NullPosition"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousParagraphEndPositionWithBoundaryBehaviorStopAtAnchorBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( // Note that for the first two tests we can't go past the line ending at // "Line 1" to test for "NullPosition'", because the text position at // the beginning of the soft line break is equivalent to the position at // the end of the line's text and so an infinite recursion will occur. - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 13 /* text_offset at end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 13 /* text_offset at end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - ROOT_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=1 text_offset=0 " - "affinity=upstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=1 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - TEXT_FIELD_ID, - 5 /* text_offset on the last character of "Line 1". */, - {"TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2", - "TextPosition anchor_id=4 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopAtAnchorBoundary); - }), - INLINE_BOX2_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2", - "TextPosition anchor_id=9 text_offset=0 " - "affinity=downstream annotated_text=<L>ine 2"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 13 /* text_offset at end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 13 /* text_offset at end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + ROOT_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=1 text_offset=0 " + "affinity=upstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=1 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + TEXT_FIELD_ID, + 5 /* text_offset on the last character of "Line 1". */, + {"TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2", + "TextPosition anchor_id=4 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 1\nLine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopAtAnchorBoundary); + }), + INLINE_BOX2_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2", + "TextPosition anchor_id=9 text_offset=0 " + "affinity=downstream annotated_text=<L>ine 2"}})); INSTANTIATE_TEST_SUITE_P( CreatePreviousParagraphEndPositionWithBoundaryBehaviorStopIfAlreadyAtBoundary, - AXPositionTestWithParam, + AXPositionTextNavigationTestWithParam, testing::Values( - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - ROOT_ID, - 12 /* text_offset one before the end of root. */, - {"TextPosition anchor_id=1 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=1 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - TEXT_FIELD_ID, - 12 /* text_offset one before the end of text field */, - {"TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2", - "TextPosition anchor_id=4 text_offset=7 " - "affinity=upstream annotated_text=Line 1\n<L>ine 2"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX1_ID, - 2 /* text_offset */, - {"TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>", - "TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 4 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - INLINE_BOX2_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - LINE_BREAK_ID, - 0 /* text_offset */, - {"TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>", - "TextPosition anchor_id=3 text_offset=0 " - "affinity=downstream annotated_text=<>"}}, - TestParam{base::BindRepeating([](const TestPositionType& position) { - return position->CreatePreviousParagraphEndPosition( - AXBoundaryBehavior::StopIfAlreadyAtBoundary); - }), - LINE_BREAK_ID, - 1 /* text_offset */, - {"TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>", - "TextPosition anchor_id=7 text_offset=1 " - "affinity=downstream annotated_text=\n<>"}})); + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + ROOT_ID, + 12 /* text_offset one before the end of root. */, + {"TextPosition anchor_id=1 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=1 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + TEXT_FIELD_ID, + 12 /* text_offset one before the end of text field */, + {"TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2", + "TextPosition anchor_id=4 text_offset=7 " + "affinity=upstream annotated_text=Line 1\n<L>ine 2"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX1_ID, + 2 /* text_offset */, + {"TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>", + "TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 4 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + INLINE_BOX2_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + LINE_BREAK_ID, + 0 /* text_offset */, + {"TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>", + "TextPosition anchor_id=3 text_offset=0 " + "affinity=downstream annotated_text=<>"}}, + TextNavigationTestParam{ + base::BindRepeating([](const TestPositionType& position) { + return position->CreatePreviousParagraphEndPosition( + AXBoundaryBehavior::StopIfAlreadyAtBoundary); + }), + LINE_BREAK_ID, + 1 /* text_offset */, + {"TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>", + "TextPosition anchor_id=7 text_offset=1 " + "affinity=downstream annotated_text=\n<>"}})); } // namespace ui
diff --git a/ui/accessibility/ax_position.h b/ui/accessibility/ax_position.h index 5e00722..a6b9d82 100644 --- a/ui/accessibility/ax_position.h +++ b/ui/accessibility/ax_position.h
@@ -23,6 +23,7 @@ #include "ui/accessibility/ax_enums.mojom.h" #include "ui/accessibility/ax_node_text_styles.h" #include "ui/accessibility/ax_role_properties.h" +#include "ui/accessibility/ax_text_boundary.h" #include "ui/accessibility/ax_tree_id.h" namespace ui { @@ -749,6 +750,190 @@ return child_position->AsLeafTextPosition(); } + // Starting from this position, moves in the given direction until it finds + // the given text boundary, and creates a new position at that location. + // + // When a boundary has the "StartOrEnd" suffix, it means that this method will + // find the start boundary when moving in the backwards direction, and the end + // boundary when moving in the forwards direction. + AXPositionInstance CreatePositionAtTextBoundary( + AXTextBoundary boundary, + AXTextBoundaryDirection direction, + AXBoundaryBehavior boundary_behavior) const { + AXPositionInstance resulting_position = CreateNullPosition(); + switch (boundary) { + case AXTextBoundary::kCharacter: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousCharacterPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextCharacterPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kFormatChange: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousFormatStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextFormatEndPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kLineEnd: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousLineEndPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextLineEndPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kLineStart: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousLineStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextLineStartPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kLineStartOrEnd: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousLineStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextLineEndPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kObject: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = CreatePositionAtStartOfAnchor(); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreatePositionAtEndOfAnchor(); + break; + } + break; + + case AXTextBoundary::kParagraphEnd: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousParagraphEndPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = + CreateNextParagraphEndPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kParagraphStart: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousParagraphStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = + CreateNextParagraphStartPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kParagraphStartOrEnd: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousParagraphStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = + CreateNextParagraphEndPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kSentenceEnd: + NOTREACHED() << "Sentence boundaries are not yet supported."; + return CreateNullPosition(); + + case AXTextBoundary::kSentenceStart: + NOTREACHED() << "Sentence boundaries are not yet supported."; + return CreateNullPosition(); + + case AXTextBoundary::kSentenceStartOrEnd: + NOTREACHED() << "Sentence boundaries are not yet supported."; + return CreateNullPosition(); + + case AXTextBoundary::kWebPage: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = CreatePositionAtStartOfDocument(); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreatePositionAtEndOfDocument(); + break; + } + break; + + case AXTextBoundary::kWordEnd: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousWordEndPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextWordEndPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kWordStart: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousWordStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextWordStartPosition(boundary_behavior); + break; + } + break; + + case AXTextBoundary::kWordStartOrEnd: + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + resulting_position = + CreatePreviousWordStartPosition(boundary_behavior); + break; + case AXTextBoundaryDirection::kForwards: + resulting_position = CreateNextWordEndPosition(boundary_behavior); + break; + } + break; + } + return resulting_position; + } + AXPositionInstance CreatePositionAtStartOfAnchor() const { switch (kind_) { case AXPositionKind::NULL_POSITION: @@ -779,19 +964,20 @@ } AXPositionInstance CreatePreviousFormatStartPosition( - ui::AXBoundaryBehavior boundary_behavior) const { - return CreatePositionAtFormatBoundary(boundary_behavior, - /*forwards*/ false); + AXBoundaryBehavior boundary_behavior) const { + return CreatePositionAtFormatBoundary(AXTextBoundaryDirection::kBackwards, + boundary_behavior); } AXPositionInstance CreateNextFormatEndPosition( - ui::AXBoundaryBehavior boundary_behavior) const { - return CreatePositionAtFormatBoundary(boundary_behavior, /*forwards*/ true); + AXBoundaryBehavior boundary_behavior) const { + return CreatePositionAtFormatBoundary(AXTextBoundaryDirection::kForwards, + boundary_behavior); } AXPositionInstance CreatePositionAtFormatBoundary( - AXBoundaryBehavior boundary_behavior, - bool forwards) const { + AXTextBoundaryDirection direction, + AXBoundaryBehavior boundary_behavior) const { // Disallow AXBoundaryBehavior::StopAtAnchorBoundary, as it would be no // different than moving by anchor DCHECK_NE(boundary_behavior, AXBoundaryBehavior::StopAtAnchorBoundary); @@ -801,21 +987,37 @@ bool was_tree_position = IsTreePosition(); AXPositionInstance initial_endpoint = AsLeafTextPosition(); - AXPositionInstance current_endpoint = - forwards ? initial_endpoint->CreateNextLeafTextPosition() - : initial_endpoint->CreatePreviousLeafTextPosition(); + AXPositionInstance current_endpoint = CreateNullPosition(); + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + current_endpoint = initial_endpoint->CreatePreviousLeafTextPosition(); + break; + case AXTextBoundaryDirection::kForwards: + current_endpoint = initial_endpoint->CreateNextLeafTextPosition(); + break; + } // Start or end of document if (current_endpoint->IsNullPosition()) { if (boundary_behavior == AXBoundaryBehavior::CrossBoundary && - ((forwards && AtEndOfAnchor()) || (!forwards && AtStartOfAnchor()))) { + ((direction == AXTextBoundaryDirection::kForwards && + AtEndOfAnchor()) || + (direction == AXTextBoundaryDirection::kBackwards && + AtStartOfAnchor()))) { // Expected behavior is to return a null position for cross-boundary // moves that hit the beginning or end of the document return std::move(current_endpoint); } - current_endpoint = - forwards ? initial_endpoint->CreatePositionAtEndOfAnchor() - : initial_endpoint->CreatePositionAtStartOfAnchor(); + + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + current_endpoint = initial_endpoint->CreatePositionAtStartOfAnchor(); + break; + case AXTextBoundaryDirection::kForwards: + current_endpoint = initial_endpoint->CreatePositionAtEndOfAnchor(); + break; + } + return was_tree_position ? current_endpoint->AsTreePosition() : std::move(current_endpoint); } @@ -826,10 +1028,13 @@ // not at the start or end of the current anchor, move to the start or // end, depending on direction. if (!was_tree_position) { - if (forwards && !initial_endpoint->AtEndOfAnchor()) + if (direction == AXTextBoundaryDirection::kForwards && + !initial_endpoint->AtEndOfAnchor()) { return initial_endpoint->CreatePositionAtEndOfAnchor(); - else if (!forwards && !initial_endpoint->AtStartOfAnchor()) + } else if (direction == AXTextBoundaryDirection::kBackwards && + !initial_endpoint->AtStartOfAnchor()) { return initial_endpoint->CreatePositionAtStartOfAnchor(); + } } // We were already at the start or end of a node on a format boundary. @@ -847,10 +1052,14 @@ auto next_endpoint = current_endpoint->Clone(); do { - if (forwards) - next_endpoint = next_endpoint->CreateNextLeafTextPosition(); - else - next_endpoint = next_endpoint->CreatePreviousLeafTextPosition(); + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + next_endpoint = next_endpoint->CreatePreviousLeafTextPosition(); + break; + case AXTextBoundaryDirection::kForwards: + next_endpoint = next_endpoint->CreateNextLeafTextPosition(); + break; + } if (next_endpoint->IsNullPosition() || next_endpoint->GetTextStyles() != initial_styles) @@ -862,10 +1071,14 @@ // Moving forwards should leave the position at the end of an anchor. // Backwards moves are already at the start of the anchor from // CreatePreviousLeafTextPosition, so there's no need to move again. - if (forwards) - current_endpoint = current_endpoint->CreatePositionAtEndOfAnchor(); - else - DCHECK(current_endpoint->AtStartOfAnchor()); + switch (direction) { + case AXTextBoundaryDirection::kBackwards: + DCHECK(current_endpoint->AtStartOfAnchor()); + break; + case AXTextBoundaryDirection::kForwards: + current_endpoint = current_endpoint->CreatePositionAtEndOfAnchor(); + break; + } if (was_tree_position) return current_endpoint->AsTreePosition(); @@ -1079,8 +1292,9 @@ DCHECK_NE(boundary_behavior, AXBoundaryBehavior::StopIfAlreadyAtBoundary) << "StopIfAlreadyAtBoundary is unreasonable for character boundaries."; if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary && - AtEndOfAnchor()) + AtEndOfAnchor()) { return Clone(); + } const bool was_tree_position = IsTreePosition(); AXPositionInstance text_position = AsPositionBeforeCharacter(); @@ -1104,8 +1318,9 @@ DCHECK_NE(boundary_behavior, AXBoundaryBehavior::StopIfAlreadyAtBoundary) << "StopIfAlreadyAtBoundary is unreasonable for character boundaries."; if (boundary_behavior == AXBoundaryBehavior::StopAtAnchorBoundary && - AtStartOfAnchor()) + AtStartOfAnchor()) { return Clone(); + } const bool was_tree_position = IsTreePosition(); AXPositionInstance text_position = AsPositionAfterCharacter();
diff --git a/ui/accessibility/ax_text_boundary.h b/ui/accessibility/ax_text_boundary.h index aa2c9f4d..e935135b 100644 --- a/ui/accessibility/ax_text_boundary.h +++ b/ui/accessibility/ax_text_boundary.h
@@ -50,6 +50,14 @@ kWordStartOrEnd, }; +// Specifies the direction to search for a text boundary. +enum class AXTextBoundaryDirection { + // Search forward for the next boundary past a given position. + kForwards, + // Search backward for the previous boundary before a given position. + kBackwards +}; + // Produces a string representation of AXTextBoundary. AX_EXPORT std::string ToString(const AXTextBoundary boundary); AX_EXPORT std::ostream& operator<<(std::ostream& stream,
diff --git a/ui/accessibility/ax_text_utils.cc b/ui/accessibility/ax_text_utils.cc index ef3e0c7..28caedf 100644 --- a/ui/accessibility/ax_text_utils.cc +++ b/ui/accessibility/ax_text_utils.cc
@@ -50,7 +50,7 @@ const std::vector<int>& line_breaks, AXTextBoundary boundary, size_t start_offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) { size_t text_size = text.size(); DCHECK_LE(start_offset, text_size); @@ -67,7 +67,7 @@ } if (boundary == AXTextBoundary::kLineStart) { - if (direction == FORWARDS_DIRECTION) { + if (direction == AXTextBoundaryDirection::kForwards) { for (size_t j = 0; j < line_breaks.size(); ++j) { size_t line_break = line_breaks[j] >= 0 ? line_breaks[j] : 0; if ((affinity == ax::mojom::TextAffinity::kDownstream && @@ -95,7 +95,7 @@ size_t result = start_offset; for (;;) { size_t pos; - if (direction == FORWARDS_DIRECTION) { + if (direction == AXTextBoundaryDirection::kForwards) { if (result >= text_size) return text_size; pos = result; @@ -113,7 +113,8 @@ if (break_iter.IsGraphemeBoundary(result)) { // If we are searching forward and we are still at the start offset, // we need to find the next character. - if (direction == BACKWARDS_DIRECTION || result != start_offset) + if (direction == AXTextBoundaryDirection::kBackwards || + result != start_offset) return result; } break; @@ -121,7 +122,8 @@ if (break_iter.IsStartOfWord(result)) { // If we are searching forward and we are still at the start offset, // we need to find the next word. - if (direction == BACKWARDS_DIRECTION || result != start_offset) + if (direction == AXTextBoundaryDirection::kBackwards || + result != start_offset) return result; } break; @@ -129,12 +131,14 @@ if (break_iter.IsStartOfWord(result)) { // If we are searching forward and we are still at the start offset, // we need to find the next word. - if (direction == BACKWARDS_DIRECTION || result != start_offset) + if (direction == AXTextBoundaryDirection::kBackwards || + result != start_offset) return result; } else if (break_iter.IsEndOfWord(result)) { // If we are searching backward and we are still at the end offset, we // need to find the previous word. - if (direction == FORWARDS_DIRECTION || result != start_offset) + if (direction == AXTextBoundaryDirection::kForwards || + result != start_offset) return result; } break; @@ -142,7 +146,8 @@ if (break_iter.IsSentenceBoundary(result)) { // If we are searching forward and we are still at the start offset, // we need to find the next sentence. - if (direction == BACKWARDS_DIRECTION || result != start_offset) { + if (direction == AXTextBoundaryDirection::kBackwards || + result != start_offset) { // ICU sometimes returns sentence boundaries in the whitespace // between sentences. For the purposes of accessibility, we want to // include all whitespace at the end of a sentence. We move the @@ -163,7 +168,7 @@ break; } - if (direction == FORWARDS_DIRECTION) { + if (direction == AXTextBoundaryDirection::kForwards) { result++; } else { result--;
diff --git a/ui/accessibility/ax_text_utils.h b/ui/accessibility/ax_text_utils.h index 2e27307..2390333 100644 --- a/ui/accessibility/ax_text_utils.h +++ b/ui/accessibility/ax_text_utils.h
@@ -16,14 +16,6 @@ namespace ui { -// A direction when searching for the next boundary. -enum TextBoundaryDirection { - // Search forwards for the next boundary past the starting position. - FORWARDS_DIRECTION, - // Search backwards for the previous boundary before the starting position. - BACKWARDS_DIRECTION -}; - // Convenience method needed to implement platform-specific text // accessibility APIs like IAccessible2. Search forwards or backwards // (depending on |direction|) from the given |start_offset| until the @@ -33,7 +25,7 @@ const std::vector<int>& line_breaks, AXTextBoundary boundary, size_t start_offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity); // Returns a string ID that corresponds to the name of the given action.
diff --git a/ui/accessibility/ax_text_utils_unittest.cc b/ui/accessibility/ax_text_utils_unittest.cc index 898ff05..94839ffa 100644 --- a/ui/accessibility/ax_text_utils_unittest.cc +++ b/ui/accessibility/ax_text_utils_unittest.cc
@@ -25,47 +25,52 @@ result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kWordStart, 0, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(6UL, result); - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kWordStart, 5, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kWordStart, 5, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(0UL, result); result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kWordStart, 6, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(12UL, result); - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kWordStart, 11, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kWordStart, 11, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(6UL, result); - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kWordStart, 12, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kWordStart, 12, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(12UL, result); result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kWordStart, 15, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(17UL, result); - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kWordStart, 15, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kWordStart, 15, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(12UL, result); result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kWordStart, 16, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(17UL, result); result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kWordStart, 17, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(20UL, result); result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kWordStart, 20, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(text_length, result); - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kWordStart, text_length, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kWordStart, text_length, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(20UL, result); } @@ -80,56 +85,61 @@ // Basic cases. result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kLineStart, 5, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(8UL, result); - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kLineStart, 9, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kLineStart, 9, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(8UL, result); result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kLineStart, 10, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // Edge cases. - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kLineStart, text_length, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kLineStart, text_length, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // When the start_offset is at the start of the next line and we are searching // backwards, it should not move. - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kLineStart, 15, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kLineStart, 15, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // When the start_offset is at a hard line break and we are searching // backwards, it should return the start of the previous line. - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kLineStart, 14, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kLineStart, 14, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(8UL, result); // When the start_offset is at the start of a line and we are searching // forwards, it should return the start of the next line. result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kLineStart, 8, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(15UL, result); // When there is no previous line break and we are searching backwards, // it should return 0. - result = FindAccessibleTextBoundary( - text, line_start_offsets, AXTextBoundary::kLineStart, 4, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + result = FindAccessibleTextBoundary(text, line_start_offsets, + AXTextBoundary::kLineStart, 4, + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(0UL, result); // When we are at the start of the last line and we are searching forwards. // it should return the text length. result = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kLineStart, 15, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(text_length, result); } @@ -139,10 +149,12 @@ std::vector<int> line_start_offsets; size_t backwards = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kSentenceStart, offset, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); size_t forwards = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kSentenceStart, offset, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, + ax::mojom::TextAffinity::kDownstream); return std::make_pair(backwards, forwards); }; @@ -222,12 +234,14 @@ std::vector<int> line_start_offsets; size_t backwards = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kCharacter, offset, - BACKWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kBackwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(backwards, start); size_t forwards = FindAccessibleTextBoundary( text, line_start_offsets, AXTextBoundary::kCharacter, offset, - FORWARDS_DIRECTION, ax::mojom::TextAffinity::kDownstream); + AXTextBoundaryDirection::kForwards, + ax::mojom::TextAffinity::kDownstream); EXPECT_EQ(forwards, end); };
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.cc b/ui/accessibility/platform/ax_platform_node_auralinux.cc index fbdd072..d5dbf14 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.cc +++ b/ui/accessibility/platform/ax_platform_node_auralinux.cc
@@ -951,9 +951,10 @@ // need to convert this input value. offset = obj->UnicodeToUTF16OffsetInText(offset); - int start_offset = - obj->FindTextBoundary(boundary, offset, BACKWARDS_DIRECTION); - int end_offset = obj->FindTextBoundary(boundary, offset, FORWARDS_DIRECTION); + int start_offset = obj->FindTextBoundary(boundary, offset, + AXTextBoundaryDirection::kBackwards); + int end_offset = obj->FindTextBoundary(boundary, offset, + AXTextBoundaryDirection::kForwards); if (start_offset < 0 || end_offset < 0) return nullptr; @@ -4212,19 +4213,19 @@ int AXPlatformNodeAuraLinux::FindStartOfStyle( int start_offset, - ui::TextBoundaryDirection direction) { + AXTextBoundaryDirection direction) { int text_length = GetHypertext().length(); DCHECK_GE(start_offset, 0); DCHECK_LE(start_offset, text_length); DCHECK(!offset_to_text_attributes_.empty()); switch (direction) { - case ui::BACKWARDS_DIRECTION: { + case AXTextBoundaryDirection::kBackwards: { auto iterator = offset_to_text_attributes_.upper_bound(start_offset); --iterator; return iterator->first; } - case ui::FORWARDS_DIRECTION: { + case AXTextBoundaryDirection::kForwards: { const auto iterator = offset_to_text_attributes_.upper_bound(start_offset); if (iterator == offset_to_text_attributes_.end()) @@ -4244,8 +4245,10 @@ DCHECK(!offset_to_text_attributes_.empty()); int utf16_offset = UnicodeToUTF16OffsetInText(offset); - int style_start = FindStartOfStyle(utf16_offset, ui::BACKWARDS_DIRECTION); - int style_end = FindStartOfStyle(utf16_offset, ui::FORWARDS_DIRECTION); + int style_start = + FindStartOfStyle(utf16_offset, AXTextBoundaryDirection::kBackwards); + int style_end = + FindStartOfStyle(utf16_offset, AXTextBoundaryDirection::kForwards); auto iterator = offset_to_text_attributes_.find(style_start); DCHECK(iterator != offset_to_text_attributes_.end());
diff --git a/ui/accessibility/platform/ax_platform_node_auralinux.h b/ui/accessibility/platform/ax_platform_node_auralinux.h index 3b08d05..ae7968fa 100644 --- a/ui/accessibility/platform/ax_platform_node_auralinux.h +++ b/ui/accessibility/platform/ax_platform_node_auralinux.h
@@ -44,6 +44,8 @@ namespace ui { +enum class AXTextBoundaryDirection; + struct FindInPageResultInfo { AtkObject* node; int start_offset; @@ -274,7 +276,7 @@ int offset, std::map<int, AtkAttributes>* text_attributes); AtkAttributes ComputeTextAttributes() const; - int FindStartOfStyle(int start_offset, ui::TextBoundaryDirection direction); + int FindStartOfStyle(int start_offset, AXTextBoundaryDirection direction); // Reset any find in page operations for the toplevel document of this node. void ForgetCurrentFindInPageResult();
diff --git a/ui/accessibility/platform/ax_platform_node_base.cc b/ui/accessibility/platform/ax_platform_node_base.cc index ab536e0..54955a4 100644 --- a/ui/accessibility/platform/ax_platform_node_base.cc +++ b/ui/accessibility/platform/ax_platform_node_base.cc
@@ -1620,7 +1620,7 @@ int AXPlatformNodeBase::FindTextBoundary( AXTextBoundary boundary, int offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) const { base::Optional<int> boundary_offset = GetDelegate()->FindTextBoundary(boundary, offset, direction, affinity);
diff --git a/ui/accessibility/platform/ax_platform_node_base.h b/ui/accessibility/platform/ax_platform_node_base.h index 6b3a553..1bf3a14a 100644 --- a/ui/accessibility/platform/ax_platform_node_base.h +++ b/ui/accessibility/platform/ax_platform_node_base.h
@@ -12,7 +12,6 @@ #include "base/macros.h" #include "build/build_config.h" #include "ui/accessibility/ax_enums.mojom.h" -#include "ui/accessibility/ax_text_utils.h" #include "ui/accessibility/platform/ax_platform_node.h" #include "ui/accessibility/platform/ax_platform_text_boundary.h" #include "ui/base/buildflags.h" @@ -254,7 +253,7 @@ // produce appropriate results. virtual int FindTextBoundary(AXTextBoundary boundary, int offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity = ax::mojom::TextAffinity::kDownstream) const;
diff --git a/ui/accessibility/platform/ax_platform_node_delegate.h b/ui/accessibility/platform/ax_platform_node_delegate.h index 5cebb45..bc47e43 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate.h +++ b/ui/accessibility/platform/ax_platform_node_delegate.h
@@ -239,7 +239,7 @@ virtual base::Optional<int> FindTextBoundary( AXTextBoundary boundary, int offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) const = 0; // Return a vector of all the descendants of this delegate's node.
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.cc b/ui/accessibility/platform/ax_platform_node_delegate_base.cc index 32f0061..b03e7b6 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate_base.cc +++ b/ui/accessibility/platform/ax_platform_node_delegate_base.cc
@@ -478,7 +478,7 @@ base::Optional<int> AXPlatformNodeDelegateBase::FindTextBoundary( AXTextBoundary boundary, int offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) const { return base::nullopt; }
diff --git a/ui/accessibility/platform/ax_platform_node_delegate_base.h b/ui/accessibility/platform/ax_platform_node_delegate_base.h index b5ed307..8f405b7 100644 --- a/ui/accessibility/platform/ax_platform_node_delegate_base.h +++ b/ui/accessibility/platform/ax_platform_node_delegate_base.h
@@ -177,7 +177,7 @@ base::Optional<int> FindTextBoundary( AXTextBoundary boundary, int offset, - TextBoundaryDirection direction, + AXTextBoundaryDirection direction, ax::mojom::TextAffinity affinity) const override; const std::vector<gfx::NativeViewAccessible> GetDescendants() const override;
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc index 96516ac..0ff304f 100644 --- a/ui/accessibility/platform/ax_platform_node_win.cc +++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -3404,10 +3404,10 @@ const base::string16& text_str = TextForIAccessibleText(); - *start_offset = - FindBoundary(text_str, boundary_type, offset, BACKWARDS_DIRECTION); - *end_offset = - FindBoundary(text_str, boundary_type, offset, FORWARDS_DIRECTION); + *start_offset = FindBoundary(text_str, boundary_type, offset, + AXTextBoundaryDirection::kBackwards); + *end_offset = FindBoundary(text_str, boundary_type, offset, + AXTextBoundaryDirection::kForwards); return get_text(*start_offset, *end_offset, text); } @@ -3431,8 +3431,8 @@ const base::string16& text_str = TextForIAccessibleText(); - *start_offset = - FindBoundary(text_str, boundary_type, offset, BACKWARDS_DIRECTION); + *start_offset = FindBoundary(text_str, boundary_type, offset, + AXTextBoundaryDirection::kBackwards); *end_offset = offset; return get_text(*start_offset, *end_offset, text); } @@ -3458,8 +3458,8 @@ const base::string16& text_str = TextForIAccessibleText(); *start_offset = offset; - *end_offset = - FindBoundary(text_str, boundary_type, offset, FORWARDS_DIRECTION); + *end_offset = FindBoundary(text_str, boundary_type, offset, + AXTextBoundaryDirection::kForwards); return get_text(*start_offset, *end_offset, text); } @@ -6837,7 +6837,7 @@ LONG AXPlatformNodeWin::FindBoundary(const base::string16& text, IA2TextBoundaryType ia2_boundary, LONG start_offset, - TextBoundaryDirection direction) { + AXTextBoundaryDirection direction) { HandleSpecialTextOffset(&start_offset); AXTextBoundary boundary = FromIA2TextBoundary(ia2_boundary); std::vector<int32_t> line_breaks;
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h index 2dfbbbc..66c70956 100644 --- a/ui/accessibility/platform/ax_platform_node_win.h +++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -304,6 +304,7 @@ *arg = {}; namespace ui { + class AXPlatformNodeWin; class AXPlatformRelationWin; @@ -1212,7 +1213,7 @@ LONG FindBoundary(const base::string16& text, IA2TextBoundaryType ia2_boundary, LONG start_offset, - TextBoundaryDirection direction); + AXTextBoundaryDirection direction); // Many MSAA methods take a var_id parameter indicating that the operation // should be performed on a particular child ID, rather than this object.
diff --git a/ui/aura/BUILD.gn b/ui/aura/BUILD.gn index 630f2c2..5a81fda3 100644 --- a/ui/aura/BUILD.gn +++ b/ui/aura/BUILD.gn
@@ -269,6 +269,7 @@ "//build/win:default_exe_manifest", "//components/viz/host", "//components/viz/service", + "//mojo/core/embedder", "//skia", "//third_party/icu", "//ui/base",
diff --git a/ui/aura/demo/DEPS b/ui/aura/demo/DEPS index 58aa4e9..44171531 100644 --- a/ui/aura/demo/DEPS +++ b/ui/aura/demo/DEPS
@@ -1,6 +1,7 @@ include_rules = [ "+components/viz/host", "+components/viz/service", # In-process viz service. + "+mojo/core/embedder/embedder.h", # TestGpuServiceHolder needs Mojo. "+ui/display", # Windows DPI Initialization. "+ui/gl/gl_switches.h", # Disable Direct Composition Workaround. "+ui/gl/init/gl_factory.h", # To initialize GL bindings.
diff --git a/ui/aura/demo/demo_main.cc b/ui/aura/demo/demo_main.cc index 9877cf7..83da4024 100644 --- a/ui/aura/demo/demo_main.cc +++ b/ui/aura/demo/demo_main.cc
@@ -19,6 +19,7 @@ #include "components/viz/host/host_frame_sink_manager.h" #include "components/viz/service/display_embedder/server_shared_bitmap_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" +#include "mojo/core/embedder/embedder.h" #include "third_party/skia/include/core/SkBlendMode.h" #include "ui/aura/client/default_capture_client.h" #include "ui/aura/client/window_parenting_client.h" @@ -223,6 +224,8 @@ // The exit manager is in charge of calling the dtors of singleton objects. base::AtExitManager exit_manager; + mojo::core::Init(); + base::i18n::InitializeICU(); return DemoMain();
diff --git a/ui/base/cocoa/menu_controller.mm b/ui/base/cocoa/menu_controller.mm index 43a13a3..647c8bb2 100644 --- a/ui/base/cocoa/menu_controller.mm +++ b/ui/base/cocoa/menu_controller.mm
@@ -166,33 +166,44 @@ ui::MenuModel::ItemType type = model->GetTypeAt(index); if (type == ui::MenuModel::TYPE_SUBMENU && model->IsVisibleAt(index)) { ui::MenuModel* submenuModel = model->GetSubmenuModelAt(index); + // If there are visible items, recursively build the submenu. NSMenu* submenu = MenuHasVisibleItems(submenuModel) ? [self menuFromModel:submenuModel] : MakeEmptySubmenu(); - [item setSubmenu:submenu]; - } - // The MenuModel works on indexes so we can't just set the command id as the - // tag like we do in other menus. Also set the represented object to be - // the model so hierarchical menus check the correct index in the correct - // model. Setting the target to |self| allows this class to participate - // in validation of the menu items. - [item setTag:index]; - [item setTarget:self]; - NSValue* modelObject = [NSValue valueWithPointer:model]; - [item setRepresentedObject:modelObject]; // Retains |modelObject|. - // On the Mac, context menus never have accelerators. Menus constructed - // for context use have useWithPopUpButtonCell_ set to NO. - if (useWithPopUpButtonCell_) { - ui::Accelerator accelerator; - if (model->GetAcceleratorAt(index, &accelerator)) { - NSString* key_equivalent; - NSUInteger modifier_mask; - GetKeyEquivalentAndModifierMaskFromAccelerator( - accelerator, &key_equivalent, &modifier_mask); - [item setKeyEquivalent:key_equivalent]; - [item setKeyEquivalentModifierMask:modifier_mask]; + [item setTarget:nil]; + [item setAction:nil]; + [item setSubmenu:submenu]; + // [item setSubmenu] updates target and action which means clicking on a + // submenu entry will not call [self validateUserInterfaceItem]. + DCHECK_EQ([item action], @selector(submenuAction:)); + DCHECK_EQ([item target], submenu); + // Set the enabled state here as submenu entries do not call into + // validateUserInterfaceItem. See crbug.com/981294 and crbug.com/991472. + [item setEnabled:model->IsEnabledAt(index)]; + } else { + // The MenuModel works on indexes so we can't just set the command id as the + // tag like we do in other menus. Also set the represented object to be + // the model so hierarchical menus check the correct index in the correct + // model. Setting the target to |self| allows this class to participate + // in validation of the menu items. + [item setTag:index]; + [item setTarget:self]; + NSValue* modelObject = [NSValue valueWithPointer:model]; + [item setRepresentedObject:modelObject]; // Retains |modelObject|. + // On the Mac, context menus never have accelerators. Menus constructed + // for context use have useWithPopUpButtonCell_ set to NO. + if (useWithPopUpButtonCell_) { + ui::Accelerator accelerator; + if (model->GetAcceleratorAt(index, &accelerator)) { + NSString* key_equivalent; + NSUInteger modifier_mask; + GetKeyEquivalentAndModifierMaskFromAccelerator( + accelerator, &key_equivalent, &modifier_mask); + [item setKeyEquivalent:key_equivalent]; + [item setKeyEquivalentModifierMask:modifier_mask]; + } } } [menu insertItem:item atIndex:index];
diff --git a/ui/base/cocoa/menu_controller_unittest.mm b/ui/base/cocoa/menu_controller_unittest.mm index c1769f2..c36ba6b 100644 --- a/ui/base/cocoa/menu_controller_unittest.mm +++ b/ui/base/cocoa/menu_controller_unittest.mm
@@ -303,7 +303,9 @@ EXPECT_EQ(3, [[menu menu] numberOfItems]); // Inspect the submenu to ensure it has correct properties. - NSMenu* submenu = [[[menu menu] itemAtIndex:1] submenu]; + NSMenuItem* menuItem = [[menu menu] itemAtIndex:1]; + EXPECT_TRUE([menuItem isEnabled]); + NSMenu* submenu = [menuItem submenu]; EXPECT_TRUE(submenu); EXPECT_EQ(3, [submenu numberOfItems]); @@ -429,11 +431,14 @@ Delegate delegate; SimpleMenuModel model(&delegate); model.AddItem(1, ASCIIToUTF16("one")); - SimpleMenuModel submodel(&delegate); - submodel.AddItem(2, ASCIIToUTF16("sub")); - model.AddSubMenuWithStringId(3, kTestLabelResourceId, &submodel); + SimpleMenuModel disabled_submodel(&delegate); + disabled_submodel.AddItem(2, ASCIIToUTF16("disabled_submodel")); + model.AddSubMenuWithStringId(3, kTestLabelResourceId, &disabled_submodel); + SimpleMenuModel enabled_submodel(&delegate); + enabled_submodel.AddItem(4, ASCIIToUTF16("enabled_submodel")); + model.AddSubMenuWithStringId(5, kTestLabelResourceId, &enabled_submodel); - // Disable the submenu entry. + // Disable the first submenu entry. model.SetEnabledAt(1, false); // Create the controller. @@ -445,9 +450,14 @@ // Show the menu. CFRunLoopPerformBlock(CFRunLoopGetCurrent(), NSEventTrackingRunLoopMode, ^{ EXPECT_TRUE([menu_controller isMenuOpen]); - // Ensure that the submenu is disabled. - NSMenuItem* item = [[menu_controller menu] itemAtIndex:1]; - EXPECT_FALSE([item isEnabled]); + + // Ensure that the disabled submenu is disabled. + NSMenuItem* disabled_item = [[menu_controller menu] itemAtIndex:1]; + EXPECT_FALSE([disabled_item isEnabled]); + + // Ensure that the enabled submenu is enabled. + NSMenuItem* enabled_item = [[menu_controller menu] itemAtIndex:2]; + EXPECT_TRUE([enabled_item isEnabled]); }); // Pop open the menu, which will spin an event-tracking run loop.
diff --git a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js index 031473f3..cccd109 100644 --- a/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js +++ b/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js
@@ -106,10 +106,18 @@ }, /** @private */ - onClick_: function() { - if (!this.readonly) { - this.$$('iron-dropdown').open(); + onClick_: function(event) { + if (this.readonly) { + return; } + + const dropdown = this.$$('iron-dropdown'); + if (event.composedPath().includes(dropdown)) { + // Ignore clicks on the dropdown element. + return; + } + + dropdown.open(); }, /** @private */