diff --git a/DEPS b/DEPS index 95500fb9..844c40ed 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'c94ff43cf846cf470b7d46e1d2aaa1724c5cc948', + 'skia_revision': '69fd008199989c5a5a96f992dcaa4089b63f490f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -64,7 +64,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '31d706bd8122830a15c574ba461e8f1a41427b9c', + 'pdfium_revision': '073797b6cff9947070077ff4b3cccc63059dc4e5', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -96,7 +96,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': '9d0d9fc4552beb4f7d5eefb4b2ecde33f58bd421', + 'catapult_revision': '1a1b45a572561a9eff29a35c9b59e2d0ff55bd4d', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other.
diff --git a/base/BUILD.gn b/base/BUILD.gn index 5c99a19..dadcf80 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -862,6 +862,8 @@ "threading/platform_thread_win.cc", "threading/post_task_and_reply_impl.cc", "threading/post_task_and_reply_impl.h", + "threading/scoped_may_block.cc", + "threading/scoped_may_block.h", "threading/sequence_local_storage_map.cc", "threading/sequence_local_storage_map.h", "threading/sequence_local_storage_slot.cc",
diff --git a/base/logging_unittest.cc b/base/logging_unittest.cc index 1d69ad7..59fdc2b 100644 --- a/base/logging_unittest.cc +++ b/base/logging_unittest.cc
@@ -269,6 +269,7 @@ } #elif defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_IOS) && \ + !defined(OS_FUCHSIA) && \ (defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY)) int g_child_crash_pipe;
diff --git a/base/nix/xdg_util.cc b/base/nix/xdg_util.cc index 41a8914..8348b06c 100644 --- a/base/nix/xdg_util.cc +++ b/base/nix/xdg_util.cc
@@ -59,6 +59,8 @@ if (env->GetVar("XDG_CURRENT_DESKTOP", &xdg_current_desktop)) { // Not all desktop environments set this env var as of this writing. if (base::StartsWith(xdg_current_desktop, "Unity", + base::CompareCase::SENSITIVE) || + base::StartsWith(xdg_current_desktop, "Pantheon", base::CompareCase::SENSITIVE)) { // gnome-fallback sessions set XDG_CURRENT_DESKTOP to Unity // DESKTOP_SESSION can be gnome-fallback or gnome-fallback-compiz
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc index 28a50d3..8d4c520 100644 --- a/base/test/launcher/unit_test_launcher.cc +++ b/base/test/launcher/unit_test_launcher.cc
@@ -373,16 +373,29 @@ fflush(stdout); // We do not have reliable details about test results (parsing test - // stdout is known to be unreliable), apply the executable exit code - // to all tests. - // TODO(phajdan.jr): Be smarter about this, e.g. retry each test - // individually. - for (size_t i = 0; i < test_names.size(); i++) { + // stdout is known to be unreliable). + if (test_names.size() == 1) { + // There is only one test. Try to determine status by exit code. + const std::string& test_name = test_names.front(); TestResult test_result; - test_result.full_name = test_names[i]; - test_result.status = TestResult::TEST_UNKNOWN; + test_result.full_name = test_name; + + if (was_timeout) { + test_result.status = TestResult::TEST_TIMEOUT; + } else if (exit_code != 0) { + test_result.status = TestResult::TEST_FAILURE; + } else { + // It's strange case when test executed successfully, + // but we failed to read machine-readable report for it. + test_result.status = TestResult::TEST_UNKNOWN; + } + test_launcher->OnTestFinished(test_result); called_any_callback = true; + } else { + // There is more than one test. Retry them individually. + for (const std::string& test_name : test_names) + tests_to_relaunch->push_back(test_name); } }
diff --git a/base/threading/scoped_may_block.cc b/base/threading/scoped_may_block.cc new file mode 100644 index 0000000..7533745 --- /dev/null +++ b/base/threading/scoped_may_block.cc
@@ -0,0 +1,42 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/threading/scoped_may_block.h" + +#include "base/lazy_instance.h" +#include "base/threading/thread_local.h" + +namespace base { + +namespace { + +LazyInstance<ThreadLocalPointer<internal::BlockingObserver>>::Leaky + tls_blocking_observer = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +namespace internal { + +void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer) { + DCHECK(!tls_blocking_observer.Get().Get()); + tls_blocking_observer.Get().Set(blocking_observer); +} + +} // namespace internal + +ScopedMayBlock::ScopedMayBlock() { + internal::BlockingObserver* blocking_observer = + tls_blocking_observer.Get().Get(); + if (blocking_observer) + blocking_observer->BlockingScopeEntered(); +} + +ScopedMayBlock::~ScopedMayBlock() { + internal::BlockingObserver* blocking_observer = + tls_blocking_observer.Get().Get(); + if (blocking_observer) + blocking_observer->BlockingScopeExited(); +} + +} // namespace base
diff --git a/base/threading/scoped_may_block.h b/base/threading/scoped_may_block.h new file mode 100644 index 0000000..284a11c --- /dev/null +++ b/base/threading/scoped_may_block.h
@@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_THREADING_SCOPED_MAY_BLOCK_H +#define BASE_THREADING_SCOPED_MAY_BLOCK_H + +#include "base/base_export.h" + +namespace base { + +// This class should be instantiated in every scope where a blocking call is +// made. +// +// Instantiation will hint the BlockingObserver for this thread about the +// scope of the blocking operation. In particular, on TaskScheduler owned +// threads, this will allow the thread to be replaced in its pool if the +// blocking scope doesn't expire shortly. +class BASE_EXPORT ScopedMayBlock { + public: + ScopedMayBlock(); + ~ScopedMayBlock(); +}; + +namespace internal { + +// Interface for an observer to be informed when a thread enters or exits +// the scope of a ScopedMayBlock object. +class BASE_EXPORT BlockingObserver { + public: + virtual void BlockingScopeEntered() = 0; + virtual void BlockingScopeExited() = 0; +}; + +void SetBlockingObserverForCurrentThread(BlockingObserver* blocking_observer); + +} // namespace internal + +} // namespace base + +#endif // BASE_THREADING_SCOPED_MAY_BLOCK_H
diff --git a/cc/base/switches.cc b/cc/base/switches.cc index d9a1c5b..a720f11 100644 --- a/cc/base/switches.cc +++ b/cc/base/switches.cc
@@ -62,13 +62,6 @@ const char kCompositedSurfaceBorders[] = "surface"; const char kCompositedLayerBorders[] = "layer"; -// TODO(dcastagna): Draw debug quad borders only when it is actually -// an overlay candidate. -// Renders a border around GL composited overlay candidate quads to -// help debug and study overlay support. -const char kGlCompositedOverlayCandidateQuadBorder[] = - "gl-composited-overlay-candidate-quad-border"; - // Draws a heads-up-display showing Frames Per Second as well as GPU memory // usage. If you also use --enable-logging=stderr --vmodule="head*=1" then FPS // will also be output to the console log. @@ -97,18 +90,6 @@ const char kEnableLayerLists[] = "enable-layer-lists"; const char kUIEnableLayerLists[] = "ui-enable-layer-lists"; -// Visualize overdraw by color-coding elements based on if they have other -// elements drawn underneath. This is good for showing where the UI might be -// doing more rendering work than necessary. The colors are hinting at the -// amount of overdraw on your screen for each pixel, as follows: -// -// True color: No overdraw. -// Blue: Overdrawn once. -// Green: Overdrawn twice. -// Pink: Overdrawn three times. -// Red: Overdrawn four or more times. -const char kShowOverdrawFeedback[] = "show-overdraw-feedback"; - // Prevents the layer tree unit tests from timing out. const char kCCLayerTreeTestNoTimeout[] = "cc-layer-tree-test-no-timeout"; @@ -118,10 +99,5 @@ // Makes pixel tests write their output instead of read it. const char kCCRebaselinePixeltests[] = "cc-rebaseline-pixeltests"; -// Disable re-use of non-exact resources to fulfill ResourcePool requests. -// Intended only for use in layout or pixel tests to reduce noise. -const char kDisallowNonExactResourceReuse[] = - "disallow-non-exact-resource-reuse"; - } // namespace switches } // namespace cc
diff --git a/cc/base/switches.h b/cc/base/switches.h index 5320fd1..420cc8b 100644 --- a/cc/base/switches.h +++ b/cc/base/switches.h
@@ -35,7 +35,6 @@ // Debug visualizations. CC_BASE_EXPORT extern const char kShowCompositedLayerBorders[]; CC_BASE_EXPORT extern const char kUIShowCompositedLayerBorders[]; -CC_BASE_EXPORT extern const char kGlCompositedOverlayCandidateQuadBorder[]; CC_BASE_EXPORT extern const char kShowFPSCounter[]; CC_BASE_EXPORT extern const char kUIShowFPSCounter[]; CC_BASE_EXPORT extern const char kShowLayerAnimationBounds[]; @@ -48,7 +47,6 @@ CC_BASE_EXPORT extern const char kUIShowScreenSpaceRects[]; CC_BASE_EXPORT extern const char kEnableLayerLists[]; CC_BASE_EXPORT extern const char kUIEnableLayerLists[]; -CC_BASE_EXPORT extern const char kShowOverdrawFeedback[]; CC_BASE_EXPORT extern const char kCompositedRenderPassBorders[]; CC_BASE_EXPORT extern const char kCompositedSurfaceBorders[]; CC_BASE_EXPORT extern const char kCompositedLayerBorders[]; @@ -57,7 +55,6 @@ CC_BASE_EXPORT extern const char kCCLayerTreeTestNoTimeout[]; CC_BASE_EXPORT extern const char kCCLayerTreeTestLongTimeout[]; CC_BASE_EXPORT extern const char kCCRebaselinePixeltests[]; -CC_BASE_EXPORT extern const char kDisallowNonExactResourceReuse[]; } // namespace switches } // namespace cc
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java index 9f95186..c9b6104 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java
@@ -288,14 +288,10 @@ if (window.hasPermission(permission.WRITE_EXTERNAL_STORAGE)) { onDownloadStartNoStream(downloadInfo); } else if (window.canRequestPermission(permission.WRITE_EXTERNAL_STORAGE)) { - PermissionCallback permissionCallback = new PermissionCallback() { - @Override - public void onRequestPermissionsResult( - String[] permissions, int[] grantResults) { - if (grantResults.length > 0 - && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - onDownloadStartNoStream(downloadInfo); - } + PermissionCallback permissionCallback = (permissions, grantResults) -> { + if (grantResults.length > 0 + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + onDownloadStartNoStream(downloadInfo); } }; window.requestPermissions(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java index 6f5a192d..3084dba 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadController.java
@@ -149,34 +149,22 @@ TextView dialogText = (TextView) view.findViewById(R.id.text); dialogText.setText(R.string.missing_storage_permission_download_education_text); - final PermissionCallback permissionCallback = new PermissionCallback() { - @Override - public void onRequestPermissionsResult(String[] permissions, int[] grantResults) { - nativeOnAcquirePermissionResult(callbackId, + final PermissionCallback permissionCallback = + (permissions, grantResults) -> nativeOnAcquirePermissionResult(callbackId, grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED, null); - } - }; AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.AlertDialogTheme) .setView(view) .setPositiveButton(R.string.infobar_update_permissions_button_text, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - windowAndroid.requestPermissions( - new String[] {permission.WRITE_EXTERNAL_STORAGE}, - permissionCallback); - } - }) - .setOnCancelListener(new DialogInterface.OnCancelListener() { - @Override - public void onCancel(DialogInterface dialog) { - nativeOnAcquirePermissionResult(callbackId, false, null); - } - }); + (DialogInterface.OnClickListener) (dialog, id) -> windowAndroid + .requestPermissions( + new String[]{permission.WRITE_EXTERNAL_STORAGE}, + permissionCallback)) + .setOnCancelListener( + dialog -> nativeOnAcquirePermissionResult(callbackId, false, null)); builder.create().show(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index b1defb22..2fd9daf 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -245,12 +245,7 @@ protected void init() { DownloadController.setDownloadNotificationService(this); // Post a delayed task to resume all pending downloads. - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - mDownloadNotifier.resumePendingDownloads(); - } - }, RESUME_DELAY_MILLIS); + mHandler.postDelayed(() -> mDownloadNotifier.resumePendingDownloads(), RESUME_DELAY_MILLIS); parseUMAStatsEntriesFromSharedPrefs(); Iterator<DownloadUmaStatsEntry> iterator = mUmaEntries.iterator(); boolean hasChanges = false; @@ -354,13 +349,9 @@ removeAutoResumableDownload(item.getId()); // Post a delayed task to avoid an issue that when connectivity status just changed // to CONNECTED, immediately establishing a connection will sometimes fail. - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - resumeDownload(LegacyHelpers.buildLegacyContentId(false, item.getId()), - item, false); - } - }, mUpdateDelayInMillis); + mHandler.postDelayed( + () -> resumeDownload(LegacyHelpers.buildLegacyContentId(false, item.getId()), + item, false), mUpdateDelayInMillis); } /** @@ -578,12 +569,9 @@ } updateAllNotifications(progressPendingUpdate); - Runnable scheduleNextUpdateTask = new Runnable(){ - @Override - public void run() { - mIsUIUpdateScheduled = false; - scheduleUpdateIfNeeded(); - } + Runnable scheduleNextUpdateTask = () -> { + mIsUIUpdateScheduled = false; + scheduleUpdateIfNeeded(); }; mHandler.postDelayed(scheduleNextUpdateTask, mUpdateDelayInMillis); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java index 624d0d8..1211b02 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadPage.java
@@ -50,13 +50,10 @@ // own ActivityStateListener. If multiple tabs are showing the downloads page, multiple // requests to check for externally removed downloads will be issued when the activity is // resumed. - mActivityStateListener = new ActivityStateListener() { - @Override - public void onActivityStateChange(Activity activity, int newState) { - if (newState == ActivityState.RESUMED) { - DownloadUtils.checkForExternallyRemovedDownloads( - mManager.getBackendProvider(), host.isIncognito()); - } + mActivityStateListener = (activity1, newState) -> { + if (newState == ActivityState.RESUMED) { + DownloadUtils.checkForExternallyRemovedDownloads( + mManager.getBackendProvider(), host.isIncognito()); } }; ApplicationStatus.registerStateListenerForActivity(mActivityStateListener, activity);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java index 69aef96..c0e6523 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadSheetContent.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.download; -import android.app.Activity; import android.view.View; import org.chromium.base.ActivityState; @@ -62,13 +61,10 @@ // own ActivityStateListener. If multiple tabs are showing the downloads page, multiple // requests to check for externally removed downloads will be issued when the activity is // resumed. - mActivityStateListener = new ActivityStateListener() { - @Override - public void onActivityStateChange(Activity activity, int newState) { - if (newState == ActivityState.RESUMED) { - DownloadUtils.checkForExternallyRemovedDownloads( - mDownloadManager.getBackendProvider(), isIncognito); - } + mActivityStateListener = (activity1, newState) -> { + if (newState == ActivityState.RESUMED) { + DownloadUtils.checkForExternallyRemovedDownloads( + mDownloadManager.getBackendProvider(), isIncognito); } }; ApplicationStatus.registerStateListenerForActivity(mActivityStateListener, activity);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java index da6478dc..d964c17 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadUtils.java
@@ -45,6 +45,7 @@ import org.chromium.chrome.browser.feature_engagement.TrackerFactory; import org.chromium.chrome.browser.offlinepages.DownloadUiActionFlags; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge; +import org.chromium.chrome.browser.offlinepages.OfflinePageOrigin; import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; import org.chromium.chrome.browser.profiles.Profile; @@ -230,17 +231,19 @@ * @param context Context to pull resources from. */ public static void downloadOfflinePage(Context context, Tab tab) { + OfflinePageOrigin origin = new OfflinePageOrigin(context, tab); + if (tab.isShowingErrorPage()) { // The download needs to be scheduled to happen at later time due to current network // error. final OfflinePageBridge bridge = OfflinePageBridge.getForProfile(tab.getProfile()); bridge.scheduleDownload(tab.getWebContents(), OfflinePageBridge.ASYNC_NAMESPACE, - tab.getUrl(), DownloadUiActionFlags.PROMPT_DUPLICATE); + tab.getUrl(), DownloadUiActionFlags.PROMPT_DUPLICATE, origin); } else { // Otherwise, the download can be started immediately. final OfflinePageDownloadBridge bridge = new OfflinePageDownloadBridge(tab.getProfile()); - bridge.startDownload(tab); + bridge.startDownload(tab, origin); bridge.destroy(); DownloadUtils.recordDownloadPageMetrics(tab); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java index 69d8742..3853a285 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/OMADownloadHandler.java
@@ -477,16 +477,13 @@ textView = (TextView) v.findViewById(R.id.oma_download_description); textView.setText(omaInfo.getValue(OMA_DESCRIPTION)); - DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == AlertDialog.BUTTON_POSITIVE) { - downloadOMAContent(downloadId, downloadInfo, omaInfo); - } else { - sendNotification(omaInfo, downloadInfo, - DownloadItem.INVALID_DOWNLOAD_ID, - DOWNLOAD_STATUS_USER_CANCELLED); - } + DialogInterface.OnClickListener clickListener = (dialog, which) -> { + if (which == AlertDialog.BUTTON_POSITIVE) { + downloadOMAContent(downloadId, downloadInfo, omaInfo); + } else { + sendNotification(omaInfo, downloadInfo, + DownloadItem.INVALID_DOWNLOAD_ID, + DOWNLOAD_STATUS_USER_CANCELLED); } }; new AlertDialog.Builder( @@ -512,13 +509,10 @@ private void showDownloadWarningDialog( int titleId, final OMAInfo omaInfo, final DownloadInfo downloadInfo, final String statusMessage) { - DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == AlertDialog.BUTTON_POSITIVE) { - sendInstallNotificationAndNextStep(omaInfo, downloadInfo, - DownloadItem.INVALID_DOWNLOAD_ID, statusMessage); - } + DialogInterface.OnClickListener clickListener = (dialog, which) -> { + if (which == AlertDialog.BUTTON_POSITIVE) { + sendInstallNotificationAndNextStep(omaInfo, downloadInfo, + DownloadItem.INVALID_DOWNLOAD_ID, statusMessage); } }; new AlertDialog.Builder( @@ -540,16 +534,13 @@ } final String nextUrl = omaInfo.getValue(OMA_NEXT_URL); final Activity activity = ApplicationStatus.getLastTrackedFocusedActivity(); - DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == AlertDialog.BUTTON_POSITIVE) { - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(nextUrl)); - intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()); - intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); - intent.setPackage(mContext.getPackageName()); - activity.startActivity(intent); - } + DialogInterface.OnClickListener clickListener = (dialog, which) -> { + if (which == AlertDialog.BUTTON_POSITIVE) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(nextUrl)); + intent.putExtra(Browser.EXTRA_APPLICATION_ID, activity.getPackageName()); + intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true); + intent.setPackage(mContext.getPackageName()); + activity.startActivity(intent); } }; new AlertDialog.Builder(activity)
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java index c2f25be..4062e11 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -497,6 +497,7 @@ /** * Schedules to download a page from |url| and categorize under |nameSpace|. * The duplicate pages or requests will be checked. + * Origin is presumed to be Chrome. * * @param webContents Web contents upon which the infobar is shown. * @param nameSpace Namespace of the page to save. @@ -505,7 +506,23 @@ */ public void scheduleDownload( WebContents webContents, String nameSpace, String url, int uiAction) { - nativeScheduleDownload(mNativeOfflinePageBridge, webContents, nameSpace, url, uiAction); + scheduleDownload(webContents, nameSpace, url, uiAction, new OfflinePageOrigin()); + } + + /** + * Schedules to download a page from |url| and categorize under |namespace| from |origin|. + * The duplicate pages or requests will be checked. + * + * @param webContents Web contents upon which the infobar is shown. + * @param nameSpace Namespace of the page to save. + * @param url URL of the page to save. + * @param uiAction UI action, like showing infobar or toast on certain case. + * @param origin Origin of the page. + */ + public void scheduleDownload(WebContents webContents, String nameSpace, String url, + int uiAction, OfflinePageOrigin origin) { + nativeScheduleDownload(mNativeOfflinePageBridge, webContents, nameSpace, url, uiAction, + origin.encodeAsJsonString()); } /** @@ -577,17 +594,18 @@ @CalledByNative private static void createOfflinePageAndAddToList(List<OfflinePageItem> offlinePagesList, String url, long offlineId, String clientNamespace, String clientId, String filePath, - long fileSize, long creationTime, int accessCount, long lastAccessTimeMs) { + long fileSize, long creationTime, int accessCount, long lastAccessTimeMs, + String requestOrigin) { offlinePagesList.add(createOfflinePageItem(url, offlineId, clientNamespace, clientId, - filePath, fileSize, creationTime, accessCount, lastAccessTimeMs)); + filePath, fileSize, creationTime, accessCount, lastAccessTimeMs, requestOrigin)); } @CalledByNative private static OfflinePageItem createOfflinePageItem(String url, long offlineId, String clientNamespace, String clientId, String filePath, long fileSize, - long creationTime, int accessCount, long lastAccessTimeMs) { - return new OfflinePageItem(url, offlineId, clientNamespace, clientId, filePath, - fileSize, creationTime, accessCount, lastAccessTimeMs); + long creationTime, int accessCount, long lastAccessTimeMs, String requestOrigin) { + return new OfflinePageItem(url, offlineId, clientNamespace, clientId, filePath, fileSize, + creationTime, accessCount, lastAccessTimeMs, requestOrigin); } @CalledByNative @@ -650,7 +668,7 @@ private native boolean nativeIsShowingDownloadButtonInErrorPage( long nativeOfflinePageBridge, WebContents webContents); private native void nativeScheduleDownload(long nativeOfflinePageBridge, - WebContents webContents, String nameSpace, String url, int uiAction); + WebContents webContents, String nameSpace, String url, int uiAction, String origin); private native boolean nativeIsOfflinePage( long nativeOfflinePageBridge, WebContents webContents); private native OfflinePageItem nativeGetOfflinePage(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java index 75af288d..3330d99 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
@@ -18,10 +18,11 @@ private final long mCreationTimeMs; private final int mAccessCount; private final long mLastAccessTimeMs; + private final String mRequestOrigin; public OfflinePageItem(String url, long offlineId, String clientNamespace, String clientId, String filePath, long fileSize, long creationTimeMs, int accessCount, - long lastAccessTimeMs) { + long lastAccessTimeMs, String requestOrigin) { mUrl = url; mOfflineId = offlineId; mClientId = new ClientId(clientNamespace, clientId); @@ -30,6 +31,7 @@ mCreationTimeMs = creationTimeMs; mAccessCount = accessCount; mLastAccessTimeMs = lastAccessTimeMs; + mRequestOrigin = requestOrigin; } /** @return URL of the offline page. */ @@ -79,4 +81,10 @@ public long getLastAccessTimeMs() { return mLastAccessTimeMs; } + + /** @return The originating application of the request. */ + @VisibleForTesting + public String getRequestOrigin() { + return mRequestOrigin; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java new file mode 100644 index 0000000..8b55c24 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java
@@ -0,0 +1,109 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.offlinepages; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.Signature; +import android.text.TextUtils; +import android.util.Base64; + +import org.json.JSONArray; + +import org.chromium.base.VisibleForTesting; +import org.chromium.chrome.browser.tab.Tab; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +/** + * Class encapsulating the application origin of a particular offline page request. + */ +public class OfflinePageOrigin { + private final String mAppName; + private final String[] mSignatures; + + /** Creates origin based on the context and tab. */ + public OfflinePageOrigin(Context context, Tab tab) { + if (TextUtils.isEmpty(tab.getAppAssociatedWith())) { + mAppName = ""; + } else { + mAppName = tab.getAppAssociatedWith(); + } + + mSignatures = getAppSignaturesFor(context, mAppName); + } + + /** Creates a Chrome origin. */ + public OfflinePageOrigin() { + this("", null); + } + + @VisibleForTesting + OfflinePageOrigin(String appName, String[] signatures) { + mAppName = appName; + mSignatures = signatures; + } + + /** + * Encode the origin information into a JSON string of + * [appName, [SHA-256 encoded signature, SHA-256 encoded signature...]] + * + * @return The JSON encoded origin information or empty string if there is + * no app information (ie assuming chrome). + */ + public String encodeAsJsonString() { + // We default to "", implying chrome-only if inputs invalid. + if (TextUtils.isEmpty(mAppName) || mSignatures == null) return ""; + // JSONArray(Object[]) requires API 19 + JSONArray signatureArray = new JSONArray(); + for (String s : mSignatures) signatureArray.put(s); + return new JSONArray().put(mAppName).put(signatureArray).toString(); + } + + /** + * @param context The context to look up signatures. + * @param appName The name of the application to look up. + * @return a sorted list of strings representing the signatures of an app. + * Null if the app name is invalid or cannot be found. + */ + private static String[] getAppSignaturesFor(Context context, String appName) { + if (TextUtils.isEmpty(appName)) return null; + try { + PackageManager packageManager = context.getPackageManager(); + Signature[] signatureList = + packageManager.getPackageInfo(appName, PackageManager.GET_SIGNATURES) + .signatures; + MessageDigest messageDigest = MessageDigest.getInstance("SHA-256"); + String[] sigStrings = new String[signatureList.length]; + for (int i = 0; i < sigStrings.length; i++) { + messageDigest.update(signatureList[i].toByteArray()); + + // The digest is reset after completing the hash computation. + sigStrings[i] = byteArrayToString(messageDigest.digest()); + } + Arrays.sort(sigStrings); + return sigStrings; + } catch (NameNotFoundException e) { + return null; // Cannot find the app anymore. No signatures. + } catch (NoSuchAlgorithmException e) { + return null; // Cannot find the SHA-256 encryption algorithm. Shouldn't happen. + } + } + + /** + * Formats bytes into a string for easier comparison. + * + * @param input Input bytes. + * @return A string representation of the input bytes, e.g., "0123456789abcdefg" + */ + private static String byteArrayToString(byte[] input) { + if (input == null) return null; + + return Base64.encodeToString(input, Base64.DEFAULT); + } +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java index 82894b9f..9684c9b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
@@ -16,6 +16,7 @@ import org.chromium.chrome.browser.download.DownloadItem; import org.chromium.chrome.browser.download.DownloadServiceDelegate; import org.chromium.chrome.browser.download.ui.BackendProvider.OfflinePageDelegate; +import org.chromium.chrome.browser.offlinepages.OfflinePageOrigin; import org.chromium.chrome.browser.offlinepages.OfflinePageUtils; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.tab.Tab; @@ -215,10 +216,12 @@ * background and killed, the background request remains that will * eventually load the page in background and obtain its offline * snapshot. + * * @param tab a tab contents of which will be saved locally. + * @param origin the object encapsulating application origin of the request. */ - public void startDownload(Tab tab) { - nativeStartDownload(mNativeOfflinePageDownloadBridge, tab); + public void startDownload(Tab tab, OfflinePageOrigin origin) { + nativeStartDownload(mNativeOfflinePageDownloadBridge, tab, origin.encodeAsJsonString()); } /** @@ -319,6 +322,6 @@ native void nativeResumeDownload(long nativeOfflinePageDownloadBridge, String guid); native void nativeDeleteItemByGuid(long nativeOfflinePageDownloadBridge, String guid); native long nativeGetOfflineIdByGuid(long nativeOfflinePageDownloadBridge, String guid); - native void nativeStartDownload(long nativeOfflinePageDownloadBridge, Tab tab); + native void nativeStartDownload(long nativeOfflinePageDownloadBridge, Tab tab, String origin); native void nativeResumePendingRequestImmediately(long nativeOfflinePageDownloadBridge); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java index 6b56beb9..1e8d388 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java
@@ -21,9 +21,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; - import java.text.SimpleDateFormat; - import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -248,16 +246,17 @@ @CalledByNative private static void createOfflinePageAndAddToList(List<OfflinePageItem> offlinePagesList, String url, long offlineId, String clientNamespace, String clientId, String filePath, - long fileSize, long creationTime, int accessCount, long lastAccessTimeMs) { + long fileSize, long creationTime, int accessCount, long lastAccessTimeMs, + String requestOrigin) { offlinePagesList.add(createOfflinePageItem(url, offlineId, clientNamespace, clientId, - filePath, fileSize, creationTime, accessCount, lastAccessTimeMs)); + filePath, fileSize, creationTime, accessCount, lastAccessTimeMs, requestOrigin)); } private static OfflinePageItem createOfflinePageItem(String url, long offlineId, String clientNamespace, String clientId, String filePath, long fileSize, - long creationTime, int accessCount, long lastAccessTimeMs) { + long creationTime, int accessCount, long lastAccessTimeMs, String requestOrigin) { return new OfflinePageItem(url, offlineId, clientNamespace, clientId, filePath, fileSize, - creationTime, accessCount, lastAccessTimeMs); + creationTime, accessCount, lastAccessTimeMs, requestOrigin); } private native long nativeCreateBridgeForProfile(
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni index f682b1f..9c2c92f 100644 --- a/chrome/android/java_sources.gni +++ b/chrome/android/java_sources.gni
@@ -691,6 +691,7 @@ "java/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTask.java", "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java", "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java", + "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageOrigin.java", "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserver.java", "java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java", "java/src/org/chromium/chrome/browser/offlinepages/SavePageRequest.java", @@ -1801,6 +1802,7 @@ "junit/src/org/chromium/chrome/browser/offlinepages/ClientIdTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/OfflineBackgroundTaskTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java", + "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageTabObserverTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtilsUnitTest.java", "junit/src/org/chromium/chrome/browser/offlinepages/ShadowDeviceConditions.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java index 77b9c75a..85576a58 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ChromeDownloadDelegateTest.java
@@ -67,14 +67,9 @@ final Tab tab = mActivityTestRule.getActivity().getActivityTab(); mActivityTestRule.loadUrl("about:blank"); ChromeDownloadDelegate delegate = ThreadUtils.runOnUiThreadBlockingNoException( - new Callable<ChromeDownloadDelegate>() { - @Override - public ChromeDownloadDelegate call() { - return new MockChromeDownloadDelegate( - InstrumentationRegistry.getInstrumentation().getTargetContext(), - tab); - } - }); + (Callable<ChromeDownloadDelegate>) () -> new MockChromeDownloadDelegate( + InstrumentationRegistry.getInstrumentation().getTargetContext(), + tab)); Assert.assertFalse(delegate.shouldInterceptContextMenuDownload("file://test/test.html")); Assert.assertFalse(delegate.shouldInterceptContextMenuDownload("http://test/test.html")); Assert.assertFalse(delegate.shouldInterceptContextMenuDownload("ftp://test/test.dm"));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java index 050810c3..1b379573c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadActivityTest.java
@@ -66,43 +66,23 @@ public void onChanged() { // To guarantee that all real Observers have had a chance to react to the event, post // the CallbackHelper.notifyCalled() call. - mHandler.post(new Runnable() { - @Override - public void run() { - onChangedCallback.notifyCalled(); - } - }); + mHandler.post(() -> onChangedCallback.notifyCalled()); } @Override public void onSelectionStateChange(List<DownloadHistoryItemWrapper> selectedItems) { mOnSelectionItems = selectedItems; - mHandler.post(new Runnable() { - @Override - public void run() { - onSelectionCallback.notifyCalled(); - } - }); + mHandler.post(() -> onSelectionCallback.notifyCalled()); } @Override public void onFilterChanged(int filter) { - mHandler.post(new Runnable() { - @Override - public void run() { - onFilterCallback.notifyCalled(); - } - }); + mHandler.post(() -> onFilterCallback.notifyCalled()); } @Override public void onSpaceDisplayUpdated(SpaceDisplay display) { - mHandler.post(new Runnable() { - @Override - public void run() { - onSpaceDisplayUpdatedCallback.notifyCalled(); - } - }); + mHandler.post(() -> onSpaceDisplayUpdatedCallback.notifyCalled()); } @Override @@ -164,12 +144,7 @@ int callCount = mAdapterObserver.onChangedCallback.getCallCount(); int spaceDisplayCallCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final DownloadItem updateItem = StubbedProvider.createDownloadItem(7, "20151021 07:28"); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.onDownloadItemCreated(updateItem); - } - }); + ThreadUtils.runOnUiThread(() -> mAdapter.onDownloadItemCreated(updateItem)); mAdapterObserver.onChangedCallback.waitForCallback(callCount, 2); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(spaceDisplayCallCount); assertEquals("6.50 GB downloaded", mSpaceUsedDisplay.getText()); @@ -179,12 +154,7 @@ spaceDisplayCallCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final DownloadItem deletedItem = StubbedProvider.createDownloadItem(6, "20151021 07:28"); deletedItem.setHasBeenExternallyRemoved(true); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.onDownloadItemUpdated(deletedItem); - } - }); + ThreadUtils.runOnUiThread(() -> mAdapter.onDownloadItemUpdated(deletedItem)); mAdapterObserver.onChangedCallback.waitForCallback(callCount, 2); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(spaceDisplayCallCount); assertEquals("5.50 GB downloaded", mSpaceUsedDisplay.getText()); @@ -194,13 +164,9 @@ spaceDisplayCallCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final OfflinePageDownloadItem deletedPage = StubbedProvider.createOfflineItem(3, "20151021 07:28"); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mStubbedProvider.getOfflinePageBridge().observer.onItemDeleted( - deletedPage.getGuid()); - } - }); + ThreadUtils.runOnUiThread( + () -> mStubbedProvider.getOfflinePageBridge().observer.onItemDeleted( + deletedPage.getGuid())); mAdapterObserver.onChangedCallback.waitForCallback(callCount, 2); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(spaceDisplayCallCount); assertEquals("512.00 MB downloaded", mSpaceUsedDisplay.getText()); @@ -262,13 +228,8 @@ assertEquals(0, mStubbedProvider.getDownloadDelegate().removeDownloadCallback.getCallCount()); assertEquals(0, mStubbedProvider.getOfflinePageBridge().deleteItemCallback.getCallCount()); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - assertTrue(mUi.getDownloadManagerToolbarForTests().getMenu() - .performIdentifierAction(R.id.selection_mode_delete_menu_id, 0)); - } - }); + ThreadUtils.runOnUiThread(() -> assertTrue(mUi.getDownloadManagerToolbarForTests().getMenu() + .performIdentifierAction(R.id.selection_mode_delete_menu_id, 0))); mStubbedProvider.getDownloadDelegate().removeDownloadCallback.waitForCallback(0); assertEquals(1, @@ -297,12 +258,9 @@ int callCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final DownloadItem item7 = StubbedProvider.createDownloadItem(7, "20161021 07:28"); final DownloadItem item8 = StubbedProvider.createDownloadItem(8, "20161021 17:28"); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.onDownloadItemCreated(item7); - mAdapter.onDownloadItemCreated(item8); - } + ThreadUtils.runOnUiThread(() -> { + mAdapter.onDownloadItemCreated(item7); + mAdapter.onDownloadItemCreated(item8); }); // The criteria is needed because an AsyncTask is fired to update the space display, which @@ -323,13 +281,8 @@ // Click the delete button. callCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - assertTrue(mUi.getDownloadManagerToolbarForTests().getMenu() - .performIdentifierAction(R.id.selection_mode_delete_menu_id, 0)); - } - }); + ThreadUtils.runOnUiThread(() -> assertTrue(mUi.getDownloadManagerToolbarForTests().getMenu() + .performIdentifierAction(R.id.selection_mode_delete_menu_id, 0))); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount); // Assert that items are temporarily removed from the adapter. The two selected items, @@ -341,12 +294,8 @@ callCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final View rootView = mUi.getView().getRootView(); assertNotNull(rootView.findViewById(R.id.snackbar)); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - rootView.findViewById(R.id.snackbar_button).callOnClick(); - } - }); + ThreadUtils.runOnUiThread( + (Runnable) () -> rootView.findViewById(R.id.snackbar_button).callOnClick()); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount); @@ -376,12 +325,9 @@ int callCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final DownloadItem item7 = StubbedProvider.createDownloadItem(7, "20161021 07:28"); final DownloadItem item8 = StubbedProvider.createDownloadItem(8, "20161021 17:28"); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mAdapter.onDownloadItemCreated(item7); - mAdapter.onDownloadItemCreated(item8); - } + ThreadUtils.runOnUiThread(() -> { + mAdapter.onDownloadItemCreated(item7); + mAdapter.onDownloadItemCreated(item8); }); // The criteria is needed because an AsyncTask is fired to update the space display, which @@ -402,13 +348,8 @@ // Click the delete button. callCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - assertTrue(mUi.getDownloadManagerToolbarForTests().getMenu() - .performIdentifierAction(R.id.selection_mode_delete_menu_id, 0)); - } - }); + ThreadUtils.runOnUiThread(() -> assertTrue(mUi.getDownloadManagerToolbarForTests().getMenu() + .performIdentifierAction(R.id.selection_mode_delete_menu_id, 0))); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount); // Assert that the two items and their date bucket are temporarily removed from the adapter. @@ -419,12 +360,8 @@ callCount = mAdapterObserver.onSpaceDisplayUpdatedCallback.getCallCount(); final View rootView = mUi.getView().getRootView(); assertNotNull(rootView.findViewById(R.id.snackbar)); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - rootView.findViewById(R.id.snackbar_button).callOnClick(); - } - }); + ThreadUtils.runOnUiThread( + (Runnable) () -> rootView.findViewById(R.id.snackbar_button).callOnClick()); mAdapterObserver.onSpaceDisplayUpdatedCallback.waitForCallback(callCount); @@ -460,12 +397,7 @@ shareIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM)); // Scroll to ensure the item at position 8 is visible. - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mRecyclerView.scrollToPosition(9); - } - }); + ThreadUtils.runOnUiThread(() -> mRecyclerView.scrollToPosition(9)); getInstrumentation().waitForIdleSync(); // Select another image, download item #0. @@ -478,12 +410,7 @@ 2, shareIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM).size()); // Scroll to ensure the item at position 5 is visible. - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mRecyclerView.scrollToPosition(6); - } - }); + ThreadUtils.runOnUiThread(() -> mRecyclerView.scrollToPosition(6)); getInstrumentation().waitForIdleSync(); // Select non-image item, download item #4. @@ -496,12 +423,7 @@ 3, shareIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM).size()); // Scroll to ensure the item at position 2 is visible. - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - mRecyclerView.scrollToPosition(3); - } - }); + ThreadUtils.runOnUiThread(() -> mRecyclerView.scrollToPosition(3)); getInstrumentation().waitForIdleSync(); // Select an offline page #3. @@ -564,12 +486,8 @@ assertTrue(mStubbedProvider.getSelectionDelegate().isSelectionEnabled()); int callCount = mAdapterObserver.onSelectionCallback.getCallCount(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - toolbar.getMenu().performIdentifierAction(R.id.search_menu_id, 0); - } - }); + ThreadUtils.runOnUiThreadBlocking( + (Runnable) () -> toolbar.getMenu().performIdentifierAction(R.id.search_menu_id, 0)); // The selection should be cleared when a search is started. mAdapterObserver.onSelectionCallback.waitForCallback(callCount, 1); @@ -587,12 +505,7 @@ assertEquals(View.VISIBLE, toolbarSearchView.getVisibility()); // Close the search view. - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - toolbar.onNavigationBack(); - } - }); + ThreadUtils.runOnUiThreadBlocking(() -> toolbar.onNavigationBack()); assertEquals(View.GONE, toolbarSearchView.getVisibility()); } @@ -626,12 +539,9 @@ private void clickOnFilter(final DownloadManagerUi ui, final int position) throws Exception { int previousCount = mAdapterObserver.onChangedCallback.getCallCount(); final Spinner spinner = mUi.getDownloadManagerToolbarForTests().getSpinnerForTests(); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - spinner.performClick(); - spinner.setSelection(position); - } + ThreadUtils.runOnUiThread(() -> { + spinner.performClick(); + spinner.setSelection(position); }); mAdapterObserver.onChangedCallback.waitForCallback(previousCount); } @@ -643,12 +553,7 @@ final DownloadItemView itemView = ((DownloadHistoryItemViewHolder) mostRecentHolder).getItemView(); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - itemView.performLongClick(); - } - }); + ThreadUtils.runOnUiThread((Runnable) () -> itemView.performLongClick()); mAdapterObserver.onSelectionCallback.waitForCallback(callCount, 1); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java index 76e1d44..192a4f5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java
@@ -88,14 +88,11 @@ * Helper method to simulate that the DownloadNotificationService is connected. */ public void onServiceConnected() { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - mService = new MockDownloadNotificationService(); - mService.setContext(new AdvancedMockContext( - mContext.getApplicationContext())); - mService.onCreate(); - } + ThreadUtils.runOnUiThreadBlocking(() -> { + mService = new MockDownloadNotificationService(); + mService.setContext(new AdvancedMockContext( + mContext.getApplicationContext())); + mService.onCreate(); }); setDownloadNotificationService(mService); } @@ -281,12 +278,8 @@ @Override protected void scheduleUpdateIfNeeded() { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadManagerServiceForTest.super.scheduleUpdateIfNeeded(); - } - }); + ThreadUtils.runOnUiThreadBlocking( + () -> DownloadManagerServiceForTest.super.scheduleUpdateIfNeeded()); } @Override @@ -412,12 +405,8 @@ MockDownloadSnackbarController snackbarController = new MockDownloadSnackbarController(); final DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadManagerService.setDownloadManagerService(dService); - } - }); + ThreadUtils.runOnUiThreadBlocking( + (Runnable) () -> DownloadManagerService.setDownloadManagerService(dService)); dService.setDownloadSnackbarController(snackbarController); // Try calling download completed directly. DownloadInfo successful = getDownloadInfo(); @@ -447,12 +436,8 @@ MockDownloadSnackbarController snackbarController = new MockDownloadSnackbarController(); final DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadManagerService.setDownloadManagerService(dService); - } - }); + ThreadUtils.runOnUiThreadBlocking( + (Runnable) () -> DownloadManagerService.setDownloadManagerService(dService)); dService.setDownloadSnackbarController(snackbarController); // Check that if an interrupted download cannot be resumed, it will trigger a download // failure.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java index 0e7e524..abb6586 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java
@@ -98,12 +98,8 @@ @Override protected void shutdownService() { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadNotificationServiceTest.super.shutdownService(); - } - }); + ThreadUtils.runOnUiThreadBlocking( + () -> DownloadNotificationServiceTest.super.shutdownService()); } @Override @@ -116,12 +112,9 @@ } private void startNotificationService() { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - Intent intent = new Intent(getService(), MockDownloadNotificationService.class); - startService(intent); - } + ThreadUtils.runOnUiThreadBlocking(() -> { + Intent intent = new Intent(getService(), MockDownloadNotificationService.class); + startService(intent); }); } @@ -138,12 +131,7 @@ } private void resumeAllDownloads(final DownloadNotificationService service) throws Exception { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - service.resumeAllPendingDownloads(); - } - }); + ThreadUtils.runOnUiThreadBlocking(() -> service.resumeAllPendingDownloads()); } /** @@ -155,12 +143,7 @@ public void testPausingWithoutOngoingDownloads() { setupService(); startNotificationService(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - getService().updateNotificationsForShutdown(); - } - }); + ThreadUtils.runOnUiThreadBlocking(() -> getService().updateNotificationsForShutdown()); assertTrue(getService().isPaused()); assertTrue(getService().getNotificationIds().isEmpty()); } @@ -199,13 +182,10 @@ getSystemContext().getApplicationContext()); DownloadResumptionScheduler.setDownloadResumptionScheduler(scheduler); setupService(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - Intent intent = new Intent(getService(), MockDownloadNotificationService.class); - intent.setAction(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL); - startService(intent); - } + ThreadUtils.runOnUiThreadBlocking(() -> { + Intent intent = new Intent(getService(), MockDownloadNotificationService.class); + intent.setAction(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL); + startService(intent); }); assertFalse(scheduler.mScheduled); } @@ -251,12 +231,7 @@ DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - getService().updateNotificationsForShutdown(); - } - }); + ThreadUtils.runOnUiThreadBlocking(() -> getService().updateNotificationsForShutdown()); assertTrue(getService().isPaused()); assertEquals(2, getService().getNotificationIds().size()); assertTrue(getService().getNotificationIds().contains(1)); @@ -285,12 +260,7 @@ DownloadSharedPreferenceHelper.KEY_PENDING_DOWNLOAD_NOTIFICATIONS, notifications); editor.apply(); startNotificationService(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - getService().updateNotificationsForShutdown(); - } - }); + ThreadUtils.runOnUiThreadBlocking(() -> getService().updateNotificationsForShutdown()); assertEquals(2, getService().getNotificationIds().size()); assertTrue(getService().getNotificationIds().contains(3)); assertTrue(getService().getNotificationIds().contains(4)); @@ -379,12 +349,8 @@ final MockDownloadManagerService manager = new MockDownloadManagerService(getSystemContext().getApplicationContext()); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadManagerService.setDownloadManagerService(manager); - } - }); + ThreadUtils.runOnUiThreadBlocking( + (Runnable) () -> DownloadManagerService.setDownloadManagerService(manager)); DownloadManagerService.setIsNetworkMeteredForTest(true); resumeAllDownloads(service); assertEquals(1, manager.mDownloads.size()); @@ -417,12 +383,7 @@ editor.apply(); startNotificationService(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - getService().onTaskRemoved(new Intent()); - } - }); + ThreadUtils.runOnUiThreadBlocking(() -> getService().onTaskRemoved(new Intent())); assertTrue(getService().isPaused()); assertFalse(sharedPrefs.contains(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java index 87c5b20e..74d9d5df 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
@@ -47,7 +47,6 @@ import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; /** * Tests Chrome download feature by attempting to download some files. @@ -175,12 +174,8 @@ Assert.assertTrue(mDownloadTestRule.hasDownload(FILENAME_GZIP, null)); CriteriaHelper.pollUiThread( - Criteria.equals(initialTabCount, new Callable<Integer>() { - @Override - public Integer call() { - return mDownloadTestRule.getActivity().getCurrentTabModel().getCount(); - } - })); + Criteria.equals(initialTabCount, + () -> mDownloadTestRule.getActivity().getCurrentTabModel().getCount())); } @Test @@ -330,12 +325,8 @@ final TabModel model = mDownloadTestRule.getActivity().getCurrentTabModel(); final int count = model.getCount(); - InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() { - @Override - public void run() { - TabModelUtils.setIndex(model, count - 1); - } - }); + InstrumentationRegistry.getInstrumentation().runOnMainSync( + (Runnable) () -> TabModelUtils.setIndex(model, count - 1)); CriteriaHelper.pollUiThread(new Criteria() { @Override @@ -438,13 +429,9 @@ try { final DownloadManagerRequestInterceptorForTest interceptor = new DownloadManagerRequestInterceptorForTest(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadManagerService.getDownloadManagerService() - .setDownloadManagerRequestInterceptor(interceptor); - } - }); + ThreadUtils.runOnUiThreadBlocking( + () -> DownloadManagerService.getDownloadManagerService() + .setDownloadManagerRequestInterceptor(interceptor)); List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>(); headers.add(Pair.create("Content-Type", "application/vnd.oma.drm.message")); final String url = webServer.setResponse("/test.dm", "testdata", headers);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java index 7cbb5a49..1781927 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java
@@ -230,26 +230,20 @@ ApplicationUtils.waitForLibraryDependencies(getInstrumentation()); final Context context = getInstrumentation().getTargetContext().getApplicationContext(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - mSavedDownloadManagerService = DownloadManagerService.setDownloadManagerService( - new TestDownloadManagerService(context, new SystemDownloadNotifier(context), - new Handler(), UPDATE_DELAY_MILLIS)); - DownloadController.setDownloadNotificationService( - DownloadManagerService.getDownloadManagerService()); - } + ThreadUtils.runOnUiThreadBlocking(() -> { + mSavedDownloadManagerService = DownloadManagerService.setDownloadManagerService( + new TestDownloadManagerService(context, new SystemDownloadNotifier(context), + new Handler(), UPDATE_DELAY_MILLIS)); + DownloadController.setDownloadNotificationService( + DownloadManagerService.getDownloadManagerService()); }); } private void tearDown() throws Exception { cleanUpAllDownloads(); - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - DownloadManagerService.setDownloadManagerService(mSavedDownloadManagerService); - DownloadController.setDownloadNotificationService(mSavedDownloadManagerService); - } + ThreadUtils.runOnUiThreadBlocking(() -> { + DownloadManagerService.setDownloadManagerService(mSavedDownloadManagerService); + DownloadController.setDownloadNotificationService(mSavedDownloadManagerService); }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java index ea483c9..1add6f5 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/MockDownloadNotificationService.java
@@ -15,7 +15,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Callable; /** * Mock class to DownloadNotificationService for testing purpose. @@ -100,14 +99,10 @@ final String fileName, final long systemDownloadId, final boolean isOffTheRecord, final boolean isSupportedMimeType, final boolean isOpenable, final Bitmap icon, final String originalUrl, final String referrer) { - return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Integer>() { - @Override - public Integer call() throws Exception { - return MockDownloadNotificationService.super.notifyDownloadSuccessful(id, filePath, + return ThreadUtils.runOnUiThreadBlockingNoException( + () -> MockDownloadNotificationService.super.notifyDownloadSuccessful(id, filePath, fileName, systemDownloadId, isOffTheRecord, isSupportedMimeType, isOpenable, - icon, originalUrl, referrer); - } - }); + icon, originalUrl, referrer)); } @Override @@ -115,34 +110,24 @@ final Progress progress, final long bytesReceived, final long timeRemainingInMillis, final long startTime, final boolean isOffTheRecord, final boolean canDownloadWhileMetered, final boolean isTransient, final Bitmap icon) { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - MockDownloadNotificationService.super.notifyDownloadProgress(id, fileName, progress, + ThreadUtils.runOnUiThreadBlocking( + () -> MockDownloadNotificationService.super.notifyDownloadProgress(id, fileName, + progress, bytesReceived, timeRemainingInMillis, startTime, isOffTheRecord, - canDownloadWhileMetered, isTransient, icon); - } - }); + canDownloadWhileMetered, isTransient, icon)); } @Override public void notifyDownloadFailed(final ContentId id, final String fileName, final Bitmap icon) { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - MockDownloadNotificationService.super.notifyDownloadFailed(id, fileName, icon); - } - }); + ThreadUtils.runOnUiThreadBlocking( + () -> MockDownloadNotificationService.super.notifyDownloadFailed(id, fileName, + icon)); } @Override public void notifyDownloadCanceled(final ContentId id) { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - MockDownloadNotificationService.super.notifyDownloadCanceled(id); - } - }); + ThreadUtils.runOnUiThreadBlocking( + () -> MockDownloadNotificationService.super.notifyDownloadCanceled(id)); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/SystemDownloadNotifierTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/SystemDownloadNotifierTest.java index a0bdf15..9f8e2843 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/SystemDownloadNotifierTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/SystemDownloadNotifierTest.java
@@ -57,13 +57,9 @@ @Override void updateDownloadNotification( final PendingNotificationInfo notificationInfo, final boolean autoRelease) { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - MockSystemDownloadNotifier.super.updateDownloadNotification( - notificationInfo, autoRelease); - } - }); + ThreadUtils.runOnUiThreadBlocking( + () -> MockSystemDownloadNotifier.super.updateDownloadNotification( + notificationInfo, autoRelease)); } } @@ -77,16 +73,13 @@ * Helper method to simulate that the DownloadNotificationService is connected. */ private void onServiceConnected() { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - mService = new MockDownloadNotificationService(); - mService.setContext( - new AdvancedMockContext(InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getApplicationContext())); - mService.onCreate(); - } + ThreadUtils.runOnUiThreadBlocking(() -> { + mService = new MockDownloadNotificationService(); + mService.setContext( + new AdvancedMockContext(InstrumentationRegistry.getInstrumentation() + .getTargetContext() + .getApplicationContext())); + mService.onCreate(); }); mDownloadNotifier.setDownloadNotificationService(mService); mDownloadNotifier.handlePendingNotifications();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java index c06f1b44..def3258 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -22,6 +22,7 @@ import org.chromium.chrome.browser.ChromeSwitches; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver; import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.SavePageCallback; +import org.chromium.chrome.browser.offlinepages.downloads.OfflinePageDownloadBridge; import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.test.ChromeActivityTestRule; import org.chromium.chrome.test.ChromeJUnit4ClassRunner; @@ -359,6 +360,48 @@ offlineIdToIgnore, asyncPages.get(0).getOfflineId()); } + @Test + @SmallTest + @RetryOnFailure + public void testDownloadPage() throws Exception { + final OfflinePageOrigin origin = + new OfflinePageOrigin("abc.xyz", new String[] {"deadbeef"}); + mActivityTestRule.loadUrl(mTestPage); + final String originString = origin.encodeAsJsonString(); + final Semaphore semaphore = new Semaphore(0); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + Assert.assertNotNull( + "Tab is null", mActivityTestRule.getActivity().getActivityTab()); + Assert.assertEquals("URL does not match requested.", mTestPage, + mActivityTestRule.getActivity().getActivityTab().getUrl()); + Assert.assertNotNull("WebContents is null", + mActivityTestRule.getActivity().getActivityTab().getWebContents()); + + // Use Downloadbridge, because scheduler does not work in test. + OfflinePageDownloadBridge downloadBridge = + new OfflinePageDownloadBridge(Profile.getLastUsedProfile()); + + mOfflinePageBridge.addObserver(new OfflinePageModelObserver() { + @Override + public void offlinePageAdded(OfflinePageItem newPage) { + mOfflinePageBridge.removeObserver(this); + semaphore.release(); + } + }); + + downloadBridge.startDownload( + mActivityTestRule.getActivity().getActivityTab(), origin); + } + }); + Assert.assertTrue("Semaphore acquire failed. Timed out.", + semaphore.tryAcquire(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + List<OfflinePageItem> pages = getAllPages(); + Assert.assertEquals(originString, pages.get(0).getRequestOrigin()); + } + // Returns offline ID. private long savePage(final int expectedResult, final String expectedUrl) throws InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java index 4809a42..1021786e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestMetricsTest.java
@@ -87,23 +87,6 @@ mPaymentRequestTestRule.clickCardUnmaskButtonAndWait( DialogInterface.BUTTON_POSITIVE, mPaymentRequestTestRule.getDismissed()); - // Make sure all the steps were logged. - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Initiated", 1)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Shown", 1)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.PayClicked", 1)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1)); - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Completed", 1)); - // Make sure the events were logged correctly. int expectedSample = Event.SHOWN | Event.PAY_CLICKED | Event.RECEIVED_INSTRUMENT_DETAILS | Event.COMPLETED | Event.HAD_INITIAL_FORM_OF_PAYMENT @@ -394,14 +377,6 @@ mPaymentRequestTestRule.triggerUIAndWait( "androidPaySkipUiBuy", mPaymentRequestTestRule.getResultReady()); - // The "SkippedShow" step should be logged instead of "Shown". - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.SkippedShow", 1)); - Assert.assertEquals(0, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Shown", 1)); - assertOnlySpecificSelectedPaymentMethodMetricLogged(SelectedPaymentMethod.ANDROID_PAY); // Make sure the events were logged correctly. @@ -435,14 +410,6 @@ R.id.close_button, mPaymentRequestTestRule.getDismissed()); mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); - // The "Shown" step should be logged, not "SkippedShow". - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Shown", 1)); - Assert.assertEquals(0, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.SkippedShow", 1)); - // Make sure the events were logged correctly. int expectedSample = Event.SHOWN | Event.USER_ABORTED | Event.HAD_INITIAL_FORM_OF_PAYMENT | Event.HAD_NECESSARY_COMPLETE_SUGGESTIONS; @@ -480,11 +447,6 @@ R.id.close_button, mPaymentRequestTestRule.getDismissed()); mPaymentRequestTestRule.expectResultContains(new String[] {"Request cancelled"}); - // Make sure "Shown" is logged only once. - Assert.assertEquals(1, - RecordHistogram.getHistogramValueCountForTesting( - "PaymentRequest.CheckoutFunnel.Shown", 1)); - // Make sure only one set of events was logged. Assert.assertEquals( 1, RecordHistogram.getHistogramTotalCountForTesting("PaymentRequest.Events"));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java index b0e57acdf..eb549e7 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSectionTest.java
@@ -889,7 +889,7 @@ } private OfflinePageItem createOfflinePageItem(String url, long offlineId) { - return new OfflinePageItem(url, offlineId, "", "", "", 0, 0, 0, 0); + return new OfflinePageItem(url, offlineId, "", "", "", 0, 0, 0, 0, ""); } private void verifyAction(
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java index fe5a1d260..d65ee2f 100644 --- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
@@ -52,10 +52,11 @@ private static final long TEST_CREATIONTIMEMS = 150; private static final int TEST_ACCESSCOUNT = 1; private static final long TEST_LASTACCESSTIMEMS = 20160314; + private static final String TEST_REQUEST_ORIGIN = "abc.xyz"; private static final OfflinePageItem TEST_OFFLINE_PAGE_ITEM = new OfflinePageItem(TEST_URL, TEST_OFFLINE_ID, TEST_NAMESPACE, TEST_ID, TEST_FILE_PATH, TEST_FILESIZE, - TEST_CREATIONTIMEMS, TEST_ACCESSCOUNT, TEST_LASTACCESSTIMEMS); + TEST_CREATIONTIMEMS, TEST_ACCESSCOUNT, TEST_LASTACCESSTIMEMS, TEST_REQUEST_ORIGIN); @Captor ArgumentCaptor<List<OfflinePageItem>> mResultArgument;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java new file mode 100644 index 0000000..46dcf381 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageOriginUnitTest.java
@@ -0,0 +1,27 @@ +// 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.chrome.browser.offlinepages; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import org.chromium.testing.local.LocalRobolectricTestRunner; + +/** Unit tests for {@link OfflinePageOrigin}. */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class OfflinePageOriginUnitTest { + @Test + public void testEncodeAsJson() { + String appName = "abc.xyz"; + String[] signatures = new String[] {"deadbeef", "00c0ffee"}; + OfflinePageOrigin origin = new OfflinePageOrigin(appName, signatures); + + assertEquals("[\"abc.xyz\",[\"deadbeef\",\"00c0ffee\"]]", origin.encodeAsJsonString()); + } +}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index fca4630..5c94611 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -1203,10 +1203,10 @@ flag_descriptions::kGlCompositedOverlayCandidateQuadBordersName, flag_descriptions::kGlCompositedOverlayCandidateQuadBordersDescription, kOsAll, - SINGLE_VALUE_TYPE(cc::switches::kGlCompositedOverlayCandidateQuadBorder)}, + SINGLE_VALUE_TYPE(switches::kGlCompositedOverlayCandidateQuadBorder)}, {"show-overdraw-feedback", flag_descriptions::kShowOverdrawFeedbackName, flag_descriptions::kShowOverdrawFeedbackDescription, kOsAll, - SINGLE_VALUE_TYPE(cc::switches::kShowOverdrawFeedback)}, + SINGLE_VALUE_TYPE(switches::kShowOverdrawFeedback)}, {"ui-disable-partial-swap", flag_descriptions::kUiPartialSwapName, flag_descriptions::kUiPartialSwapDescription, kOsAll, SINGLE_DISABLE_VALUE_TYPE(switches::kUIDisablePartialSwap)},
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc index 17e3aa7..ca1a48c 100644 --- a/chrome/browser/android/ntp/content_suggestions_notification_helper.cc +++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.cc
@@ -30,9 +30,24 @@ namespace { -bool IsDisabledForProfile(Profile* profile) { +// Whether auto opt out is enabled. Note that this does not disable collection +// of data required for auto opt out. +const bool kEnableAutoOptOutDefault = true; +const char kEnableAutoOptOutParamName[] = "enable_auto_opt_out"; + +bool IsAutoOptOutEnabled() { + return variations::GetVariationParamByFeatureAsBool( + ntp_snippets::kNotificationsFeature, kEnableAutoOptOutParamName, + kEnableAutoOptOutDefault); +} + +bool IsEnabledForProfile(Profile* profile) { PrefService* prefs = profile->GetPrefs(); if (!prefs->GetBoolean(prefs::kContentSuggestionsNotificationsEnabled)) { + return false; + } + + if (!IsAutoOptOutEnabled()) { return true; } @@ -41,7 +56,7 @@ int limit = variations::GetVariationParamByFeatureAsInt( kNotificationsFeature, kNotificationsIgnoredLimitParam, kNotificationsIgnoredDefaultLimit); - return current >= limit; + return current < limit; } } // namespace @@ -100,9 +115,9 @@ Java_ContentSuggestionsNotificationHelper_flushCachedMetrics(env); } -bool ContentSuggestionsNotificationHelper::IsDisabledForProfile( +bool ContentSuggestionsNotificationHelper::IsEnabledForProfile( Profile* profile) { - return ntp_snippets::IsDisabledForProfile(profile); + return ntp_snippets::IsEnabledForProfile(profile); } static void RecordNotificationOptOut(JNIEnv* env, @@ -166,7 +181,7 @@ CONTENT_SUGGESTIONS_HIDE_SHUTDOWN); } - const bool was_disabled = IsDisabledForProfile(profile); + const bool was_enabled = IsEnabledForProfile(profile); if (tap_count == 0) { // There were no taps, consecutive_ignored has not been reset and continues // from where it left off. If there was a tap, then Java has provided us @@ -176,8 +191,8 @@ } prefs->SetInteger(prefs::kContentSuggestionsConsecutiveIgnoredPrefName, consecutive_ignored); - const bool is_disabled = IsDisabledForProfile(profile); - if (!was_disabled && is_disabled) { + const bool is_enabled = IsEnabledForProfile(profile); + if (was_enabled && !is_enabled) { RecordContentSuggestionsNotificationOptOut(CONTENT_SUGGESTIONS_IMPLICIT); } }
diff --git a/chrome/browser/android/ntp/content_suggestions_notification_helper.h b/chrome/browser/android/ntp/content_suggestions_notification_helper.h index be7b35c..a5d1695 100644 --- a/chrome/browser/android/ntp/content_suggestions_notification_helper.h +++ b/chrome/browser/android/ntp/content_suggestions_notification_helper.h
@@ -45,9 +45,9 @@ // is computed in turn from that. static void FlushCachedMetrics(); - // True if the user has ignored enough notifications that we no longer think - // that the user is interested in them. - static bool IsDisabledForProfile(Profile* profile); + // False if auto opt out is enabled and the user has ignored enough + // notifications that we no longer think that the user is interested in them. + static bool IsEnabledForProfile(Profile* profile); private: DISALLOW_IMPLICIT_CONSTRUCTORS(ContentSuggestionsNotificationHelper);
diff --git a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc index b970049a..40cbbb5f 100644 --- a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc +++ b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
@@ -121,7 +121,7 @@ if (!ShouldNotifyInState(app_status_listener_.GetState())) { DVLOG(1) << "Suppressed notification because Chrome is frontmost"; return; - } else if (ContentSuggestionsNotificationHelper::IsDisabledForProfile( + } else if (!ContentSuggestionsNotificationHelper::IsEnabledForProfile( profile_)) { DVLOG(1) << "Suppressed notification due to opt-out"; return;
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc index a896fc1c..0219a03 100644 --- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc +++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -97,7 +97,8 @@ void SavePageIfNotNavigatedAway(const GURL& url, const GURL& original_url, - const ScopedJavaGlobalRef<jobject>& j_tab_ref) { + const ScopedJavaGlobalRef<jobject>& j_tab_ref, + const std::string& origin) { content::WebContents* web_contents = GetWebContentsFromJavaTab(j_tab_ref); if (!web_contents) return; @@ -129,6 +130,7 @@ params.availability = RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER; params.original_url = original_url; + params.request_origin = origin; request_id = request_coordinator->SavePageLater(params); } else { DVLOG(1) << "SavePageIfNotNavigatedAway has no valid coordinator."; @@ -153,7 +155,7 @@ } return; } - tab_helper->ObserveAndDownloadCurrentPage(client_id, request_id); + tab_helper->ObserveAndDownloadCurrentPage(client_id, request_id, origin); OfflinePageNotificationBridge notification_bridge; notification_bridge.ShowDownloadingToast(); @@ -162,9 +164,10 @@ void DuplicateCheckDone(const GURL& url, const GURL& original_url, const ScopedJavaGlobalRef<jobject>& j_tab_ref, + const std::string& origin, OfflinePageUtils::DuplicateCheckResult result) { if (result == OfflinePageUtils::DuplicateCheckResult::NOT_FOUND) { - SavePageIfNotNavigatedAway(url, original_url, j_tab_ref); + SavePageIfNotNavigatedAway(url, original_url, j_tab_ref, origin); return; } @@ -175,7 +178,8 @@ bool duplicate_request_exists = result == OfflinePageUtils::DuplicateCheckResult::DUPLICATE_REQUEST_FOUND; OfflinePageInfoBarDelegate::Create( - base::Bind(&SavePageIfNotNavigatedAway, url, original_url, j_tab_ref), + base::Bind(&SavePageIfNotNavigatedAway, url, original_url, j_tab_ref, + origin), url, duplicate_request_exists, web_contents); } @@ -389,7 +393,8 @@ void OfflinePageDownloadBridge::StartDownload( JNIEnv* env, const JavaParamRef<jobject>& obj, - const JavaParamRef<jobject>& j_tab) { + const JavaParamRef<jobject>& j_tab, + const JavaParamRef<jstring>& j_origin) { TabAndroid* tab = TabAndroid::GetNativeTab(env, j_tab); if (!tab) return; @@ -401,6 +406,7 @@ GURL url = web_contents->GetLastCommittedURL(); if (url.is_empty()) return; + std::string origin = ConvertJavaStringToUTF8(env, j_origin); GURL original_url = offline_pages::OfflinePageUtils::GetOriginalURLFromWebContents( @@ -421,7 +427,7 @@ OfflinePageUtils::CheckDuplicateDownloads( tab->GetProfile()->GetOriginalProfile(), url, - base::Bind(&DuplicateCheckDone, url, original_url, j_tab_ref)); + base::Bind(&DuplicateCheckDone, url, original_url, j_tab_ref, origin)); } void OfflinePageDownloadBridge::CancelDownload(
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h index c5416da..6576fca 100644 --- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h +++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h
@@ -55,10 +55,10 @@ const base::android::JavaParamRef<jobject>& obj, const base::android::JavaParamRef<jstring>& j_guid); - void StartDownload( - JNIEnv* env, - const base::android::JavaParamRef<jobject>& obj, - const base::android::JavaParamRef<jobject>& j_tab); + void StartDownload(JNIEnv* env, + const base::android::JavaParamRef<jobject>& obj, + const base::android::JavaParamRef<jobject>& j_tab, + const base::android::JavaParamRef<jstring>& j_origin); void CancelDownload(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj,
diff --git a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc index 6ec53df5..27e429b 100644 --- a/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc +++ b/chrome/browser/android/offline_pages/evaluation/offline_page_evaluation_bridge.cc
@@ -65,7 +65,8 @@ ConvertUTF8ToJavaString(env, offline_page.client_id.id), ConvertUTF8ToJavaString(env, offline_page.file_path.value()), offline_page.file_size, offline_page.creation_time.ToJavaTime(), - offline_page.access_count, offline_page.last_access_time.ToJavaTime()); + offline_page.access_count, offline_page.last_access_time.ToJavaTime(), + ConvertUTF8ToJavaString(env, offline_page.request_origin)); } }
diff --git a/chrome/browser/extensions/error_console/error_console_browsertest.cc b/chrome/browser/extensions/error_console/error_console_browsertest.cc index b86771f..c8efca97 100644 --- a/chrome/browser/extensions/error_console/error_console_browsertest.cc +++ b/chrome/browser/extensions/error_console/error_console_browsertest.cc
@@ -450,10 +450,12 @@ std::string message; bool use_native_bindings = FeatureSwitch::native_crx_bindings()->IsEnabled(); if (use_native_bindings) { - // TODO(devlin): The "Error in event handler for browserAction.onClicked" - // portion may or may not be worth preserving. In most cases, it's - // unnecessary with the line number, but it could be useful in some cases. - message = "Uncaught ReferenceError: baz is not defined"; + // TODO(devlin): The specific event name (here, 'browserAction.onClicked') + // may or may not be worth preserving. In most cases, it's unnecessary with + // the line number, but it could be useful in some cases. + message = + "Error in event handler: ReferenceError: " + "baz is not defined"; } else { message = "Error in event handler for browserAction.onClicked: "
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.cc b/chrome/browser/offline_pages/android/offline_page_bridge.cc index 38d0e1af..2047073 100644 --- a/chrome/browser/offline_pages/android/offline_page_bridge.cc +++ b/chrome/browser/offline_pages/android/offline_page_bridge.cc
@@ -64,7 +64,8 @@ ConvertUTF8ToJavaString(env, offline_page.client_id.id), ConvertUTF8ToJavaString(env, offline_page.file_path.value()), offline_page.file_size, offline_page.creation_time.ToJavaTime(), - offline_page.access_count, offline_page.last_access_time.ToJavaTime()); + offline_page.access_count, offline_page.last_access_time.ToJavaTime(), + ConvertUTF8ToJavaString(env, offline_page.request_origin)); } } @@ -78,7 +79,8 @@ ConvertUTF8ToJavaString(env, offline_page.client_id.id), ConvertUTF8ToJavaString(env, offline_page.file_path.value()), offline_page.file_size, offline_page.creation_time.ToJavaTime(), - offline_page.access_count, offline_page.last_access_time.ToJavaTime()); + offline_page.access_count, offline_page.last_access_time.ToJavaTime(), + ConvertUTF8ToJavaString(env, offline_page.request_origin)); } ScopedJavaLocalRef<jobject> ToJavaDeletedPageInfo( @@ -676,13 +678,15 @@ const base::android::JavaParamRef<jobject>& j_web_contents, const JavaParamRef<jstring>& j_namespace, const JavaParamRef<jstring>& j_url, - int ui_action) { + int ui_action, + const JavaParamRef<jstring>& j_origin) { content::WebContents* web_contents = content::WebContents::FromJavaWebContents(j_web_contents); OfflinePageUtils::ScheduleDownload( web_contents, ConvertJavaStringToUTF8(env, j_namespace), GURL(ConvertJavaStringToUTF8(env, j_url)), - static_cast<OfflinePageUtils::DownloadUIActionFlags>(ui_action)); + static_cast<OfflinePageUtils::DownloadUIActionFlags>(ui_action), + ConvertJavaStringToUTF8(env, j_origin)); } jboolean OfflinePageBridge::IsOfflinePage(
diff --git a/chrome/browser/offline_pages/android/offline_page_bridge.h b/chrome/browser/offline_pages/android/offline_page_bridge.h index c802f69..a23497d4 100644 --- a/chrome/browser/offline_pages/android/offline_page_bridge.h +++ b/chrome/browser/offline_pages/android/offline_page_bridge.h
@@ -153,7 +153,8 @@ const base::android::JavaParamRef<jobject>& j_web_contents, const base::android::JavaParamRef<jstring>& j_namespace, const base::android::JavaParamRef<jstring>& j_url, - int ui_action); + int ui_action, + const base::android::JavaParamRef<jstring>& j_origin); base::android::ScopedJavaGlobalRef<jobject> java_ref() { return java_ref_; }
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper.cc b/chrome/browser/offline_pages/offline_page_tab_helper.cc index 99f48640f..06420a5e 100644 --- a/chrome/browser/offline_pages/offline_page_tab_helper.cc +++ b/chrome/browser/offline_pages/offline_page_tab_helper.cc
@@ -223,12 +223,13 @@ content::WebContents* web_contents, const std::string& name_space, const GURL& url, - OfflinePageUtils::DownloadUIActionFlags ui_action) { + OfflinePageUtils::DownloadUIActionFlags ui_action, + const std::string& request_origin) { OfflinePageUtils::CheckDuplicateDownloads( web_contents->GetBrowserContext(), url, base::Bind(&OfflinePageTabHelper::DuplicateCheckDoneForScheduleDownload, weak_ptr_factory_.GetWeakPtr(), web_contents, name_space, url, - ui_action)); + ui_action, request_origin)); } void OfflinePageTabHelper::DuplicateCheckDoneForScheduleDownload( @@ -236,6 +237,7 @@ const std::string& name_space, const GURL& url, OfflinePageUtils::DownloadUIActionFlags ui_action, + const std::string& request_origin, OfflinePageUtils::DuplicateCheckResult result) { if (result != OfflinePageUtils::DuplicateCheckResult::NOT_FOUND) { if (static_cast<int>(ui_action) & @@ -244,7 +246,7 @@ OfflinePageUtils::ShowDuplicatePrompt( base::Bind(&OfflinePageTabHelper::DoDownloadPageLater, weak_ptr_factory_.GetWeakPtr(), web_contents, name_space, - url, ui_action), + url, ui_action, request_origin), url, result == OfflinePageUtils::DuplicateCheckResult::DUPLICATE_REQUEST_FOUND, @@ -253,14 +255,15 @@ } } - DoDownloadPageLater(web_contents, name_space, url, ui_action); + DoDownloadPageLater(web_contents, name_space, url, ui_action, request_origin); } void OfflinePageTabHelper::DoDownloadPageLater( content::WebContents* web_contents, const std::string& name_space, const GURL& url, - OfflinePageUtils::DownloadUIActionFlags ui_action) { + OfflinePageUtils::DownloadUIActionFlags ui_action, + const std::string& request_origin) { offline_pages::RequestCoordinator* request_coordinator = offline_pages::RequestCoordinatorFactory::GetForBrowserContext( web_contents->GetBrowserContext()); @@ -270,6 +273,7 @@ offline_pages::RequestCoordinator::SavePageLaterParams params; params.url = url; params.client_id = offline_pages::ClientId(name_space, base::GenerateGUID()); + params.request_origin = request_origin; request_coordinator->SavePageLater(params); if (static_cast<int>(ui_action) &
diff --git a/chrome/browser/offline_pages/offline_page_tab_helper.h b/chrome/browser/offline_pages/offline_page_tab_helper.h index 66757cd..dd6e662 100644 --- a/chrome/browser/offline_pages/offline_page_tab_helper.h +++ b/chrome/browser/offline_pages/offline_page_tab_helper.h
@@ -57,11 +57,11 @@ // OfflinePageTabHelper instance is tied with the associated |web_contents| // and thus the callback will be automatically invalidated if |web_contents| // is gone. - void ScheduleDownloadHelper( - content::WebContents* web_contents, - const std::string& name_space, - const GURL& url, - OfflinePageUtils::DownloadUIActionFlags ui_action); + void ScheduleDownloadHelper(content::WebContents* web_contents, + const std::string& name_space, + const GURL& url, + OfflinePageUtils::DownloadUIActionFlags ui_action, + const std::string& request_origin); private: friend class content::WebContentsUserData<OfflinePageTabHelper>; @@ -99,11 +99,13 @@ const std::string& name_space, const GURL& url, OfflinePageUtils::DownloadUIActionFlags ui_action, + const std::string& request_origin, OfflinePageUtils::DuplicateCheckResult result); void DoDownloadPageLater(content::WebContents* web_contents, const std::string& name_space, const GURL& url, - OfflinePageUtils::DownloadUIActionFlags ui_action); + OfflinePageUtils::DownloadUIActionFlags ui_action, + const std::string& request_origin); // The provisional info about the offline page being loaded. This is set when // the offline interceptor decides to serve the offline page and it will be
diff --git a/chrome/browser/offline_pages/offline_page_utils.cc b/chrome/browser/offline_pages/offline_page_utils.cc index b847891d..c86158d 100644 --- a/chrome/browser/offline_pages/offline_page_utils.cc +++ b/chrome/browser/offline_pages/offline_page_utils.cc
@@ -283,14 +283,24 @@ void OfflinePageUtils::ScheduleDownload(content::WebContents* web_contents, const std::string& name_space, const GURL& url, - DownloadUIActionFlags ui_action) { + DownloadUIActionFlags ui_action, + const std::string& request_origin) { DCHECK(web_contents); OfflinePageTabHelper* tab_helper = OfflinePageTabHelper::FromWebContents(web_contents); if (!tab_helper) return; - tab_helper->ScheduleDownloadHelper(web_contents, name_space, url, ui_action); + tab_helper->ScheduleDownloadHelper(web_contents, name_space, url, ui_action, + request_origin); +} + +// static +void OfflinePageUtils::ScheduleDownload(content::WebContents* web_contents, + const std::string& name_space, + const GURL& url, + DownloadUIActionFlags ui_action) { + ScheduleDownload(web_contents, name_space, url, ui_action, ""); } // static
diff --git a/chrome/browser/offline_pages/offline_page_utils.h b/chrome/browser/offline_pages/offline_page_utils.h index e35769b3..1d6dc7a 100644 --- a/chrome/browser/offline_pages/offline_page_utils.h +++ b/chrome/browser/offline_pages/offline_page_utils.h
@@ -127,6 +127,12 @@ static void ScheduleDownload(content::WebContents* web_contents, const std::string& name_space, const GURL& url, + DownloadUIActionFlags ui_action, + const std::string& request_origin); + + static void ScheduleDownload(content::WebContents* web_contents, + const std::string& name_space, + const GURL& url, DownloadUIActionFlags ui_action); // Determines if offline page download should be triggered based on MIME type
diff --git a/chrome/browser/offline_pages/recent_tab_helper.cc b/chrome/browser/offline_pages/recent_tab_helper.cc index e036808e..1473a65 100644 --- a/chrome/browser/offline_pages/recent_tab_helper.cc +++ b/chrome/browser/offline_pages/recent_tab_helper.cc
@@ -67,8 +67,10 @@ struct RecentTabHelper::SnapshotProgressInfo { public: // For a downloads snapshot request, where the |request_id| is defined. - SnapshotProgressInfo(const ClientId& client_id, int64_t request_id) - : client_id(client_id), request_id(request_id) {} + SnapshotProgressInfo(const ClientId& client_id, + int64_t request_id, + const std::string& origin) + : client_id(client_id), request_id(request_id), origin(origin) {} // For a last_n snapshot request. explicit SnapshotProgressInfo(const ClientId& client_id) @@ -89,6 +91,10 @@ // valid for successfully saved snapshots. SnapshotController::PageQuality expected_page_quality = SnapshotController::PageQuality::POOR; + + // The app that created the tab - either a package name of the CCT origin + // or empty, meaning chrome. + std::string origin = ""; }; RecentTabHelper::RecentTabHelper(content::WebContents* web_contents) @@ -107,13 +113,14 @@ delegate_ = std::move(delegate); } -void RecentTabHelper::ObserveAndDownloadCurrentPage( - const ClientId& client_id, int64_t request_id) { +void RecentTabHelper::ObserveAndDownloadCurrentPage(const ClientId& client_id, + int64_t request_id, + const std::string& origin) { // Note: as this implementation only supports one client namespace, enforce // that the call is from Downloads. DCHECK_EQ(kDownloadNamespace, client_id.name_space); auto new_downloads_snapshot_info = - base::MakeUnique<SnapshotProgressInfo>(client_id, request_id); + base::MakeUnique<SnapshotProgressInfo>(client_id, request_id, origin); // If this tab helper is not enabled, immediately give the job back to // RequestCoordinator. @@ -388,7 +395,8 @@ DCHECK(!downloads_ongoing_snapshot_info_); downloads_ongoing_snapshot_info_ = base::MakeUnique<SnapshotProgressInfo>( downloads_latest_saved_snapshot_info_->client_id, - downloads_latest_saved_snapshot_info_->request_id); + downloads_latest_saved_snapshot_info_->request_id, + downloads_latest_saved_snapshot_info_->origin); std::vector<int64_t> ids{downloads_latest_saved_snapshot_info_->request_id}; ContinueSnapshotWithIdsToPurge(downloads_ongoing_snapshot_info_.get(), ids); } else { @@ -439,6 +447,7 @@ save_page_params.is_background = false; save_page_params.original_url = OfflinePageUtils::GetOriginalURLFromWebContents(web_contents()); + save_page_params.request_origin = snapshot_info->origin; page_model_->SavePage( save_page_params, delegate_->CreatePageArchiver(web_contents()), base::Bind(&RecentTabHelper::SavePageCallback,
diff --git a/chrome/browser/offline_pages/recent_tab_helper.h b/chrome/browser/offline_pages/recent_tab_helper.h index 63bdeb4..a211f81 100644 --- a/chrome/browser/offline_pages/recent_tab_helper.h +++ b/chrome/browser/offline_pages/recent_tab_helper.h
@@ -87,7 +87,8 @@ // Note #2: Currently this method only accepts download requests from the // downloads namespace. void ObserveAndDownloadCurrentPage(const ClientId& client_id, - int64_t request_id); + int64_t request_id, + const std::string& origin); private: struct SnapshotProgressInfo;
diff --git a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc index 5967261..f7077d5 100644 --- a/chrome/browser/offline_pages/recent_tab_helper_unittest.cc +++ b/chrome/browser/offline_pages/recent_tab_helper_unittest.cc
@@ -342,7 +342,7 @@ FastForwardSnapshotController(); recent_tab_helper()->WasHidden(); recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 123L); + 123L, ""); RunUntilIdle(); EXPECT_TRUE(model()->is_loaded()); // No page should be captured. @@ -368,7 +368,7 @@ // But the following download request should work normally recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 123L); + 123L, ""); RunUntilIdle(); EXPECT_EQ(1U, page_added_count()); ASSERT_EQ(1U, GetAllPages().size()); @@ -392,7 +392,7 @@ // But the following download request should work normally recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 123L); + 123L, ""); RunUntilIdle(); EXPECT_EQ(1U, page_added_count()); ASSERT_EQ(1U, GetAllPages().size()); @@ -608,7 +608,7 @@ const int64_t second_offline_id = first_offline_id + 1; const ClientId second_client_id = NewDownloadClientId(); recent_tab_helper()->ObserveAndDownloadCurrentPage(second_client_id, - second_offline_id); + second_offline_id, ""); RunUntilIdle(); EXPECT_EQ(3U, page_added_count()); EXPECT_EQ(1U, model_removed_count()); @@ -623,7 +623,7 @@ const int64_t third_offline_id = first_offline_id + 2; const ClientId third_client_id = NewDownloadClientId(); recent_tab_helper()->ObserveAndDownloadCurrentPage(third_client_id, - third_offline_id); + third_offline_id, ""); RunUntilIdle(); EXPECT_EQ(4U, page_added_count()); EXPECT_EQ(1U, model_removed_count()); @@ -644,7 +644,7 @@ FastForwardSnapshotController(); recent_tab_helper()->WasHidden(); recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 123L); + 123L, ""); RunUntilIdle(); EXPECT_TRUE(model()->is_loaded()); ASSERT_EQ(0U, GetAllPages().size()); @@ -665,7 +665,7 @@ ASSERT_EQ(0U, GetAllPages().size()); recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 123L); + 123L, ""); RunUntilIdle(); // No page should be captured. ASSERT_EQ(1U, GetAllPages().size()); @@ -678,7 +678,7 @@ // so far. NavigateAndCommit(kTestPageUrl); const ClientId client_id = NewDownloadClientId(); - recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L, ""); FastForwardSnapshotController(); EXPECT_TRUE(model()->is_loaded()); ASSERT_EQ(0U, GetAllPages().size()); @@ -715,7 +715,7 @@ ASSERT_EQ(0U, GetAllPages().size()); const ClientId client_id = NewDownloadClientId(); - recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L, ""); RunUntilIdle(); ASSERT_EQ(1U, GetAllPages().size()); const OfflinePageItem& page = GetAllPages()[0]; @@ -740,13 +740,34 @@ ASSERT_EQ(0U, GetAllPages().size()); const ClientId client_id = NewDownloadClientId(); - recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L, ""); RunUntilIdle(); ASSERT_EQ(1U, GetAllPages().size()); const OfflinePageItem& page = GetAllPages()[0]; EXPECT_EQ(kTestPageUrl, page.url); EXPECT_EQ(client_id, page.client_id); EXPECT_EQ(153L, page.offline_id); + EXPECT_EQ("", page.request_origin); +} + +// Simulates a download request to offline the current page made after loading +// is completed. Should end up with one offline page. +TEST_F(RecentTabHelperTest, DownloadRequestAfterFullyLoadWithOrigin) { + NavigateAndCommit(kTestPageUrl); + recent_tab_helper()->DocumentOnLoadCompletedInMainFrame(); + FastForwardSnapshotController(); + EXPECT_TRUE(model()->is_loaded()); + ASSERT_EQ(0U, GetAllPages().size()); + + const ClientId client_id = NewDownloadClientId(); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, 153L, "abc"); + RunUntilIdle(); + ASSERT_EQ(1U, GetAllPages().size()); + const OfflinePageItem& page = GetAllPages()[0]; + EXPECT_EQ(kTestPageUrl, page.url); + EXPECT_EQ(client_id, page.client_id); + EXPECT_EQ(153L, page.offline_id); + EXPECT_EQ("abc", page.request_origin); } // Simulates requests coming from last_n and downloads at the same time for a @@ -759,7 +780,7 @@ const int64_t download_offline_id = 153L; const ClientId download_client_id = NewDownloadClientId(); recent_tab_helper()->ObserveAndDownloadCurrentPage(download_client_id, - download_offline_id); + download_offline_id, ""); RunUntilIdle(); ASSERT_EQ(2U, GetAllPages().size()); @@ -818,9 +839,10 @@ NavigateAndCommit(kTestPageUrl); const ClientId client_id_1 = NewDownloadClientId(); const int64_t offline_id_1 = 153L; - recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id_1, offline_id_1); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id_1, offline_id_1, + ""); recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 351L); + 351L, ""); // Finish loading the page. Only the first request should be executed. recent_tab_helper()->DocumentOnLoadCompletedInMainFrame(); @@ -836,9 +858,10 @@ // generate a snapshot. const ClientId client_id_3 = NewDownloadClientId(); const int64_t offline_id_3 = 789L; - recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id_3, offline_id_3); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id_3, offline_id_3, + ""); recent_tab_helper()->ObserveAndDownloadCurrentPage(NewDownloadClientId(), - 987L); + 987L, ""); RunUntilIdle(); EXPECT_EQ(2U, page_added_count()); EXPECT_EQ(0U, model_removed_count()); @@ -876,7 +899,7 @@ // Now create a download request and check the snapshot is properly created. const ClientId client_id = NewDownloadClientId(); const int64_t offline_id = 153L; - recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, offline_id); + recent_tab_helper()->ObserveAndDownloadCurrentPage(client_id, offline_id, ""); RunUntilIdle(); EXPECT_EQ(3U, page_added_count()); EXPECT_EQ(1U, model_removed_count());
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js index 9695eda..f7c3a6bd 100644 --- a/chrome/browser/resources/local_ntp/local_ntp.js +++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -218,11 +218,34 @@ /** + * Updates the OneGoogleBar (if it is loaded) based on the current theme. + * @private + */ +function renderOneGoogleBarTheme() { + if (!window.gbar) { + return; + } + try { + var oneGoogleBarApi = window.gbar.a; + var oneGoogleBarPromise = oneGoogleBarApi.bf(); + oneGoogleBarPromise.then(function(oneGoogleBar) { + var isThemeDark = getIsThemeDark(ntpApiHandle.themeBackgroundInfo); + var setForegroundStyle = oneGoogleBar.pc.bind(oneGoogleBar); + setForegroundStyle(isThemeDark ? 1 : 0); + }); + } catch (err) { + console.log('Failed setting OneGoogleBar theme:\n' + err); + } +} + + +/** * Callback for embeddedSearch.newTabPage.onthemechange. * @private */ function onThemeChange() { renderTheme(); + renderOneGoogleBarTheme(); } @@ -685,6 +708,8 @@ inHeadScript.appendChild(document.createTextNode(ogb.inHeadScript)); document.head.appendChild(inHeadScript); + renderOneGoogleBarTheme(); + var ogElem = $('one-google'); ogElem.innerHTML = ogb.barHtml; ogElem.classList.remove('hidden');
diff --git a/chrome/browser/resources/offline_pages/offline_internals.html b/chrome/browser/resources/offline_pages/offline_internals.html index 7220e63a..6aae579 100644 --- a/chrome/browser/resources/offline_pages/offline_internals.html +++ b/chrome/browser/resources/offline_pages/offline_internals.html
@@ -56,10 +56,21 @@ <th>Namespace</th> <th>Size (Kb)</th> <th>Expired</th> + <th>Request Origin</th> </tr> </thead> <tbody id="stored-pages"> </tbody> </table> + <template id="stored-pages-table-row"> + <tr> + <td><input type="checkbox" name="stored"></td> + <td><a></a></td> + <td></td> + <td></td> + <td></td> + <td></td> + </tr> + </template> <div id="page-actions-info" class="dump"></div> <h2>Request Queue</h2> @@ -74,10 +85,20 @@ <th>URL</th> <th>Created Timestamp</th> <th>Status</th> + <th>Request Origin</th> </tr> </thead> <tbody id="request-queue"> </tbody> </table> + <template id="request-queue-table-row"> + <tr> + <td><input type="checkbox" name="requests"></td> + <td></td> + <td></td> + <td></td> + <td></td> + </tr> + </template> <div id="request-queue-actions-info" class="dump"></div> <input id="url" type="url" placeholder="http://www.url1.com, http://www.url2.com, ...">
diff --git a/chrome/browser/resources/offline_pages/offline_internals.js b/chrome/browser/resources/offline_pages/offline_internals.js index 5acddb5..dc589404 100644 --- a/chrome/browser/resources/offline_pages/offline_internals.js +++ b/chrome/browser/resources/offline_pages/offline_internals.js
@@ -33,37 +33,22 @@ var storedPagesTable = $('stored-pages'); storedPagesTable.textContent = ''; + var template = $('stored-pages-table-row'); + var td = template.content.querySelectorAll('td'); for (var i = 0; i < pages.length; i++) { - var row = document.createElement('tr'); - - var checkboxCell = document.createElement('td'); - var checkbox = document.createElement('input'); - checkbox.setAttribute('type', 'checkbox'); - checkbox.setAttribute('name', 'stored'); + var checkbox = td[0].querySelector('input'); checkbox.setAttribute('value', pages[i].id); - checkboxCell.appendChild(checkbox); - row.appendChild(checkboxCell); - - var cell = document.createElement('td'); - var link = document.createElement('a'); + var link = td[1].querySelector('a'); link.setAttribute('href', pages[i].onlineUrl); link.textContent = pages[i].onlineUrl; - cell.appendChild(link); - row.appendChild(cell); - cell = document.createElement('td'); - cell.textContent = pages[i].namespace; - row.appendChild(cell); + td[2].textContent = pages[i].namespace; + td[3].textContent = Math.round(pages[i].size / 1024); + td[4].textContent = pages[i].isExpired; + td[5].textContent = pages[i].requestOrigin; - cell = document.createElement('td'); - cell.textContent = Math.round(pages[i].size / 1024); - row.appendChild(cell); - - cell = document.createElement('td'); - cell.textContent = pages[i].isExpired; - row.appendChild(cell); - + var row = document.importNode(template.content, true); storedPagesTable.appendChild(row); } offlinePages = pages; @@ -78,30 +63,18 @@ var requestQueueTable = $('request-queue'); requestQueueTable.textContent = ''; + var template = $('request-queue-table-row'); + var td = template.content.querySelectorAll('td'); for (var i = 0; i < requests.length; i++) { - var row = document.createElement('tr'); - - var checkboxCell = document.createElement('td'); - var checkbox = document.createElement('input'); - checkbox.setAttribute('type', 'checkbox'); - checkbox.setAttribute('name', 'requests'); + var checkbox = td[0].querySelector('input'); checkbox.setAttribute('value', requests[i].id); - checkboxCell.appendChild(checkbox); - row.appendChild(checkboxCell); + td[1].textContent = requests[i].onlineUrl; + td[2].textContent = new Date(requests[i].creationTime); + td[3].textContent = requests[i].status; + td[4].textContent = requests[i].requestOrigin; - var cell = document.createElement('td'); - cell.textContent = requests[i].onlineUrl; - row.appendChild(cell); - - cell = document.createElement('td'); - cell.textContent = new Date(requests[i].creationTime); - row.appendChild(cell); - - cell = document.createElement('td'); - cell.textContent = requests[i].status; - row.appendChild(cell); - + var row = document.importNode(template.content, true); requestQueueTable.appendChild(row); } savePageRequests = requests;
diff --git a/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js b/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js index 81d58c11..14777fc 100644 --- a/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js +++ b/chrome/browser/resources/offline_pages/offline_internals_browser_proxy.js
@@ -12,7 +12,8 @@ * filePath: string, * lastAccessTime: number, * accessCount: number, - * isExpired: string + * isExpired: string, + * requestOrigin: string * }} */ var OfflinePage; @@ -24,7 +25,8 @@ * creationTime: number, * id: string, * namespace: string, - * lastAttempt: number + * lastAttempt: number, + * requestOrigin: string * }} */ var SavePageRequest;
diff --git a/chrome/browser/sessions/session_restore.cc b/chrome/browser/sessions/session_restore.cc index b84ce84..768e980 100644 --- a/chrome/browser/sessions/session_restore.cc +++ b/chrome/browser/sessions/session_restore.cc
@@ -224,8 +224,7 @@ DCHECK(!use_new_window); web_contents = chrome::ReplaceRestoredTab( browser, tab.navigations, selected_index, true, tab.extension_app_id, - nullptr, tab.user_agent_override); - SessionRestore::OnWillRestoreTab(web_contents); + nullptr, tab.user_agent_override, true /* from_session_restore */); } else { int tab_index = use_new_window ? 0 : browser->tab_strip_model()->active_index() + 1; @@ -233,8 +232,8 @@ browser, tab.navigations, tab_index, selected_index, tab.extension_app_id, disposition == WindowOpenDisposition::NEW_FOREGROUND_TAB, // selected - tab.pinned, true, nullptr, tab.user_agent_override); - SessionRestore::OnWillRestoreTab(web_contents); + tab.pinned, true, nullptr, tab.user_agent_override, + true /* from_session_restore */); // Start loading the tab immediately. web_contents->GetController().LoadIfNecessary(); } @@ -596,7 +595,8 @@ WebContents* web_contents = chrome::AddRestoredTab( browser, tab.navigations, tab_index, selected_index, tab.extension_app_id, is_selected_tab, tab.pinned, true, - session_storage_namespace.get(), tab.user_agent_override); + session_storage_namespace.get(), tab.user_agent_override, + true /* from_session_restore */); // Regression check: if the current tab |is_selected_tab|, it should load // immediately, otherwise, tabs should not start loading right away. The // focused tab will be loaded by Browser, and TabLoader will load the rest. @@ -606,8 +606,6 @@ if (!web_contents) return; - SessionRestore::OnWillRestoreTab(web_contents); - // Sanitize the last active time. base::TimeDelta delta = highest_time - tab.last_active_time; web_contents->SetLastActiveTime(now - delta);
diff --git a/chrome/browser/sessions/session_restore.h b/chrome/browser/sessions/session_restore.h index 77fa7c0a..e2310e1a 100644 --- a/chrome/browser/sessions/session_restore.h +++ b/chrome/browser/sessions/session_restore.h
@@ -113,6 +113,9 @@ // without session restore started. static void OnTabLoaderFinishedLoadingTabs(); + // Is called when session restore is going to restore a tab. + static void OnWillRestoreTab(content::WebContents* web_contents); + private: friend class SessionRestoreImpl; FRIEND_TEST_ALL_PREFIXES(SessionRestoreObserverTest, SingleSessionRestore); @@ -152,9 +155,6 @@ // the first session restore. static void NotifySessionRestoreStartedLoadingTabs(); - // Is called when session restore is going to restore a tab. - static void OnWillRestoreTab(content::WebContents* web_contents); - // Contains all registered observers for session restore events. static SessionRestoreObserverList* observers_;
diff --git a/chrome/browser/sessions/session_restore_observer_browsertest.cc b/chrome/browser/sessions/session_restore_observer_browsertest.cc new file mode 100644 index 0000000..e9af8fc3 --- /dev/null +++ b/chrome/browser/sessions/session_restore_observer_browsertest.cc
@@ -0,0 +1,241 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sessions/session_restore_observer.h" + +#include <memory> +#include <unordered_map> + +#include "base/memory/ptr_util.h" +#include "build/build_config.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" +#include "chrome/browser/prefs/session_startup_pref.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/resource_coordinator/tab_manager.h" +#include "chrome/browser/sessions/session_restore.h" +#include "chrome/browser/sessions/session_service_factory.h" +#include "chrome/browser/sessions/session_service_test_helper.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_commands.h" +#include "chrome/browser/ui/browser_tabstrip.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/test/base/in_process_browser_test.h" +#include "chrome/test/base/ui_test_utils.h" +#include "content/public/browser/navigation_handle.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/test/browser_test_utils.h" +#include "testing/gtest/include/gtest/gtest.h" + +using content::WebContents; +using content::NavigationHandle; + +// This class records session-restore states of a tab when it starts navigation. +class NavigationStartWebContentsObserver : public content::WebContentsObserver { + public: + explicit NavigationStartWebContentsObserver(WebContents* contents) + : WebContentsObserver(contents) {} + + // content::WebContentsObserver implementation: + void DidStartNavigation(NavigationHandle* navigation_handle) override { + WebContents* contents = navigation_handle->GetWebContents(); + resource_coordinator::TabManager* tab_manager = + g_browser_process->GetTabManager(); + ASSERT_TRUE(tab_manager); + + is_session_restored_ = tab_manager->IsTabInSessionRestore(contents); + is_restored_in_foreground_ = + tab_manager->IsTabRestoredInForeground(contents); + } + + // Returns the session-restore states at the navigation start. + bool is_session_restored() const { return is_session_restored_; } + bool is_restored_in_foreground() const { return is_restored_in_foreground_; } + + private: + bool is_session_restored_ = false; + bool is_restored_in_foreground_ = false; + + DISALLOW_COPY_AND_ASSIGN(NavigationStartWebContentsObserver); +}; + +class MockSessionRestoreObserver : public SessionRestoreObserver { + public: + MockSessionRestoreObserver() { SessionRestore::AddObserver(this); } + ~MockSessionRestoreObserver() { SessionRestore::RemoveObserver(this); } + + enum class SessionRestoreEvent { kStartedLoadingTabs, kFinishedLoadingTabs }; + + const std::vector<SessionRestoreEvent>& session_restore_events() const { + return session_restore_events_; + } + + // SessionRestoreObserver implementation: + void OnSessionRestoreStartedLoadingTabs() override { + session_restore_events_.emplace_back( + SessionRestoreEvent::kStartedLoadingTabs); + } + void OnSessionRestoreFinishedLoadingTabs() override { + session_restore_events_.emplace_back( + SessionRestoreEvent::kFinishedLoadingTabs); + } + void OnWillRestoreTab(WebContents* contents) override { + navigation_start_observers_.emplace( + contents, new NavigationStartWebContentsObserver(contents)); + } + + NavigationStartWebContentsObserver* + GetNavigationStartWebContentsObserverForTab(WebContents* contents) { + return navigation_start_observers_[contents].get(); + } + + private: + std::vector<SessionRestoreEvent> session_restore_events_; + std::unordered_map<WebContents*, + std::unique_ptr<NavigationStartWebContentsObserver>> + navigation_start_observers_; + + DISALLOW_COPY_AND_ASSIGN(MockSessionRestoreObserver); +}; + +class SessionRestoreObserverTest : public InProcessBrowserTest { + protected: + SessionRestoreObserverTest() {} + + void SetUpOnMainThread() override { + SessionStartupPref pref(SessionStartupPref::LAST); + SessionStartupPref::SetStartupPref(browser()->profile(), pref); +#if defined(OS_CHROMEOS) + SessionServiceTestHelper helper( + SessionServiceFactory::GetForProfile(browser()->profile())); + helper.SetForceBrowserNotAliveWithNoWindows(true); + helper.ReleaseService(); +#endif + ASSERT_TRUE(embedded_test_server()->Start()); + } + + Browser* QuitBrowserAndRestore(Browser* browser) { + Profile* profile = browser->profile(); + + std::unique_ptr<ScopedKeepAlive> keep_alive(new ScopedKeepAlive( + KeepAliveOrigin::SESSION_RESTORE, KeepAliveRestartOption::DISABLED)); + CloseBrowserSynchronously(browser); + + // Create a new window, which should trigger session restore. + chrome::NewEmptyWindow(profile); + ui_test_utils::BrowserAddedObserver window_observer; + return window_observer.WaitForSingleNewBrowser(); + } + + void WaitForTabsToLoad(Browser* browser) { + for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { + WebContents* contents = browser->tab_strip_model()->GetWebContentsAt(i); + contents->GetController().LoadIfNecessary(); + ASSERT_TRUE(content::WaitForLoadStop(contents)); + } + } + + GURL GetTestURL() const { + return embedded_test_server()->GetURL("/title1.html"); + } + + const std::vector<MockSessionRestoreObserver::SessionRestoreEvent>& + session_restore_events() const { + return mock_observer_.session_restore_events(); + } + + size_t number_of_session_restore_events() const { + return session_restore_events().size(); + } + + MockSessionRestoreObserver& session_restore_observer() { + return mock_observer_; + } + + private: + MockSessionRestoreObserver mock_observer_; + + DISALLOW_COPY_AND_ASSIGN(SessionRestoreObserverTest); +}; + +IN_PROC_BROWSER_TEST_F(SessionRestoreObserverTest, SingleTabSessionRestore) { + ui_test_utils::NavigateToURL(browser(), GetTestURL()); + Browser* new_browser = QuitBrowserAndRestore(browser()); + + // The restored browser should have 1 tab. + TabStripModel* tab_strip = new_browser->tab_strip_model(); + ASSERT_TRUE(tab_strip); + ASSERT_EQ(1, tab_strip->count()); + + ASSERT_EQ(1u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::kStartedLoadingTabs, + session_restore_events()[0]); + + ASSERT_NO_FATAL_FAILURE(WaitForTabsToLoad(new_browser)); + ASSERT_EQ(2u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::kFinishedLoadingTabs, + session_restore_events()[1]); + + // The only restored tab should be in foreground. + NavigationStartWebContentsObserver* observer = + session_restore_observer().GetNavigationStartWebContentsObserverForTab( + new_browser->tab_strip_model()->GetWebContentsAt(0)); + EXPECT_TRUE(observer->is_session_restored()); + EXPECT_TRUE(observer->is_restored_in_foreground()); + + // A new foreground tab should not be created by session restore. + ui_test_utils::NavigateToURLWithDisposition( + new_browser, GetTestURL(), WindowOpenDisposition::NEW_FOREGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + resource_coordinator::TabManager* tab_manager = + g_browser_process->GetTabManager(); + WebContents* contents = new_browser->tab_strip_model()->GetWebContentsAt(1); + ASSERT_TRUE(contents); + EXPECT_FALSE(tab_manager->IsTabInSessionRestore(contents)); + EXPECT_FALSE(tab_manager->IsTabRestoredInForeground(contents)); +} + +IN_PROC_BROWSER_TEST_F(SessionRestoreObserverTest, MultipleTabSessionRestore) { + ui_test_utils::NavigateToURL(browser(), GetTestURL()); + ui_test_utils::NavigateToURLWithDisposition( + browser(), GetTestURL(), WindowOpenDisposition::NEW_BACKGROUND_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + Browser* new_browser = QuitBrowserAndRestore(browser()); + + // The restored browser should have 2 tabs. + TabStripModel* tab_strip = new_browser->tab_strip_model(); + ASSERT_TRUE(tab_strip); + ASSERT_EQ(2, tab_strip->count()); + + ASSERT_EQ(1u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::kStartedLoadingTabs, + session_restore_events()[0]); + + ASSERT_NO_FATAL_FAILURE(WaitForTabsToLoad(new_browser)); + ASSERT_EQ(2u, number_of_session_restore_events()); + EXPECT_EQ( + MockSessionRestoreObserver::SessionRestoreEvent::kFinishedLoadingTabs, + session_restore_events()[1]); + + // The first tab should be restored in foreground. + NavigationStartWebContentsObserver* observer = + session_restore_observer().GetNavigationStartWebContentsObserverForTab( + new_browser->tab_strip_model()->GetWebContentsAt(0)); + ASSERT_TRUE(observer); + EXPECT_TRUE(observer->is_session_restored()); + EXPECT_TRUE(observer->is_restored_in_foreground()); + + // The second tab should be restored in background. + observer = + session_restore_observer().GetNavigationStartWebContentsObserverForTab( + new_browser->tab_strip_model()->GetWebContentsAt(1)); + ASSERT_TRUE(observer); + EXPECT_TRUE(observer->is_session_restored()); + EXPECT_FALSE(observer->is_restored_in_foreground()); +}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn index d76ff2b..a68303b3 100644 --- a/chrome/browser/ui/BUILD.gn +++ b/chrome/browser/ui/BUILD.gn
@@ -2761,8 +2761,6 @@ "cocoa/content_settings/cookies_tree_controller_bridge.h", "cocoa/content_settings/cookies_tree_controller_bridge.mm", "cocoa/create_native_web_modal_manager_cocoa.mm", - "cocoa/custom_frame_view.h", - "cocoa/custom_frame_view.mm", "cocoa/dev_tools_controller.h", "cocoa/dev_tools_controller.mm", "cocoa/device_chooser_content_view_cocoa.h", @@ -2855,8 +2853,6 @@ "cocoa/floating_bar_backing_view.mm", "cocoa/framed_browser_window.h", "cocoa/framed_browser_window.mm", - "cocoa/full_size_content_window.h", - "cocoa/full_size_content_window.mm", "cocoa/fullscreen/fullscreen_menubar_tracker.h", "cocoa/fullscreen/fullscreen_menubar_tracker.mm", "cocoa/fullscreen/fullscreen_toolbar_animation_controller.h", @@ -3085,6 +3081,8 @@ "cocoa/tab_dialogs_views_mac.mm", "cocoa/tab_modal_confirm_dialog_mac.h", "cocoa/tab_modal_confirm_dialog_mac.mm", + "cocoa/tabbed_browser_window.h", + "cocoa/tabbed_browser_window.mm", "cocoa/tabs/alert_indicator_button_cocoa.h", "cocoa/tabs/alert_indicator_button_cocoa.mm", "cocoa/tabs/tab_controller.h",
diff --git a/chrome/browser/ui/browser_live_tab_context.cc b/chrome/browser/ui/browser_live_tab_context.cc index bf3672f1..6b679473 100644 --- a/chrome/browser/ui/browser_live_tab_context.cc +++ b/chrome/browser/ui/browser_live_tab_context.cc
@@ -76,7 +76,8 @@ WebContents* web_contents = chrome::AddRestoredTab( browser_, navigations, tab_index, selected_navigation, extension_app_id, - select, pin, from_last_session, storage_namespace, user_agent_override); + select, pin, from_last_session, storage_namespace, user_agent_override, + false /* from_session_restore */); #if BUILDFLAG(ENABLE_SESSION_SERVICE) // The focused tab will be loaded by Browser, and TabLoader will load the @@ -115,7 +116,8 @@ WebContents* web_contents = chrome::ReplaceRestoredTab( browser_, navigations, selected_navigation, from_last_session, - extension_app_id, storage_namespace, user_agent_override); + extension_app_id, storage_namespace, user_agent_override, + false /* from_session_restore */); return sessions::ContentLiveTab::GetForWebContents(web_contents); }
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc index 2b9c5b57..40c875d 100644 --- a/chrome/browser/ui/browser_tabrestore.cc +++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -6,6 +6,7 @@ #include "chrome/browser/extensions/tab_helper.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sessions/session_restore.h" #include "chrome/browser/sessions/session_service.h" #include "chrome/browser/sessions/session_service_factory.h" #include "chrome/browser/tab_contents/tab_util.h" @@ -45,7 +46,8 @@ bool from_last_session, content::SessionStorageNamespace* session_storage_namespace, const std::string& user_agent_override, - bool initially_hidden) { + bool initially_hidden, + bool from_session_restore) { GURL restore_url = navigations.at(selected_navigation).virtual_url(); // TODO(ajwong): Remove the temporary session_storage_namespace_map when // we teach session restore to understand that one tab can have multiple @@ -67,6 +69,8 @@ WebContents* web_contents = content::WebContents::CreateWithSessionStorage( create_params, session_storage_namespace_map); + if (from_session_restore) + SessionRestore::OnWillRestoreTab(web_contents); extensions::TabHelper::CreateForWebContents(web_contents); extensions::TabHelper::FromWebContents(web_contents)-> SetExtensionAppById(extension_app_id); @@ -94,15 +98,12 @@ bool pin, bool from_last_session, content::SessionStorageNamespace* session_storage_namespace, - const std::string& user_agent_override) { - WebContents* web_contents = CreateRestoredTab(browser, - navigations, - selected_navigation, - extension_app_id, - from_last_session, - session_storage_namespace, - user_agent_override, - !select); + const std::string& user_agent_override, + bool from_session_restore) { + WebContents* web_contents = CreateRestoredTab( + browser, navigations, selected_navigation, extension_app_id, + from_last_session, session_storage_namespace, user_agent_override, + !select, from_session_restore); int add_types = select ? TabStripModel::ADD_ACTIVE : TabStripModel::ADD_NONE; @@ -144,15 +145,12 @@ bool from_last_session, const std::string& extension_app_id, content::SessionStorageNamespace* session_storage_namespace, - const std::string& user_agent_override) { - WebContents* web_contents = CreateRestoredTab(browser, - navigations, - selected_navigation, - extension_app_id, - from_last_session, - session_storage_namespace, - user_agent_override, - false); + const std::string& user_agent_override, + bool from_session_restore) { + WebContents* web_contents = CreateRestoredTab( + browser, navigations, selected_navigation, extension_app_id, + from_last_session, session_storage_namespace, user_agent_override, false, + from_session_restore); // ReplaceWebContentsAt won't animate in the restoration, so manually do the // equivalent of ReplaceWebContentsAt.
diff --git a/chrome/browser/ui/browser_tabrestore.h b/chrome/browser/ui/browser_tabrestore.h index 79fa951..acf877a1 100644 --- a/chrome/browser/ui/browser_tabrestore.h +++ b/chrome/browser/ui/browser_tabrestore.h
@@ -22,17 +22,18 @@ namespace chrome { -// Add a tab with its session history restored from the SessionRestore -// system. If select is true, the tab is selected. |tab_index| gives the index -// to insert the tab at. |selected_navigation| is the index of the -// SerializedNavigationEntry in |navigations| to select. If |extension_app_id| -// is non-empty the tab is an app tab and |extension_app_id| is the id of the -// extension. If |pin| is true and |tab_index|/ is the last pinned tab, then -// the newly created tab is pinned. If |from_last_session| is true, -// |navigations| are from the previous session. |user_agent_override| contains -// the string being used as the user agent for all of the tab's navigations when -// the regular user agent is overridden. Returns the WebContents of the restored -// tab. +// Add a tab with its session history restored from the SessionRestore and +// TabRestoreService systems. If select is true, the tab is selected. +// |tab_index| gives the index to insert the tab at. |selected_navigation| is +// the index of the SerializedNavigationEntry in |navigations| to select. If +// |extension_app_id| is non-empty the tab is an app tab and |extension_app_id| +// is the id of the extension. If |pin| is true and |tab_index|/ is the last +// pinned tab, then the newly created tab is pinned. If |from_last_session| is +// true, |navigations| are from the previous session. |user_agent_override| +// contains the string being used as the user agent for all of the tab's +// navigations when the regular user agent is overridden. If +// |from_session_restore| is true, the restored tab is created by session +// restore. Returns the WebContents of the restored tab. content::WebContents* AddRestoredTab( Browser* browser, const std::vector<sessions::SerializedNavigationEntry>& navigations, @@ -43,11 +44,12 @@ bool pin, bool from_last_session, content::SessionStorageNamespace* storage_namespace, - const std::string& user_agent_override); + const std::string& user_agent_override, + bool from_session_restore); // Replaces the state of the currently selected tab with the session -// history restored from the SessionRestore system. Returns the WebContents of -// the restored tab. +// history restored from the SessionRestore and TabRestoreService systems. +// Returns the WebContents of the restored tab. content::WebContents* ReplaceRestoredTab( Browser* browser, const std::vector<sessions::SerializedNavigationEntry>& navigations, @@ -55,8 +57,8 @@ bool from_last_session, const std::string& extension_app_id, content::SessionStorageNamespace* session_storage_namespace, - const std::string& user_agent_override); - + const std::string& user_agent_override, + bool from_session_restore); } // namespace chrome
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm index df42604..3a6339a9 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -26,7 +26,6 @@ #import "chrome/browser/ui/cocoa/browser_window_fullscreen_transition.h" #import "chrome/browser/ui/cocoa/browser_window_layout.h" #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h" -#import "chrome/browser/ui/cocoa/custom_frame_view.h" #import "chrome/browser/ui/cocoa/dev_tools_controller.h" #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h" @@ -61,6 +60,16 @@ using content::RenderWidgetHostView; using content::WebContents; +@interface NSView (PrivateAPI) +// Returns the fullscreen button's origin in window coordinates. This method is +// only available on NSThemeFrame (the contentView's superview), and it should +// not be relied on to exist on macOS >10.9 (which doesn't have a separate +// fullscreen button). TabbedBrowserWindow's NSThemeFrame subclass centers it +// vertically in the tabstrip (if there is a tabstrip), and shifts it to the +// left of the old-style avatar icon if necessary. +- (NSPoint)_fullScreenButtonOrigin; +@end + namespace { // The screen on which the window was fullscreened, and whether the device had
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm index fdb74647..8f553ce 100644 --- a/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/browser_window_controller_unittest.mm
@@ -760,15 +760,7 @@ TEST_F(BrowserWindowControllerTest, UsesAutoLayout) { // If Auto Layout is on, there will be synthesized constraints based on the // view's frame and autoresizing mask. - // TODO(sdy): Turn back on (or remove) after investigating a performance - // regression: https://crbug.com/706931 - if (chrome::ShouldUseFullSizeContentView()) { - // FramedBrowserWindow relies on Auto Layout to position the window buttons - // when using a full size content view. - EXPECT_NE(0u, [[[controller_ chromeContentView] constraints] count]); - } else { - EXPECT_EQ(0u, [[[controller_ chromeContentView] constraints] count]); - } + EXPECT_EQ(0u, [[[controller_ chromeContentView] constraints] count]); } @interface BrowserWindowControllerFakeFullscreen : BrowserWindowController {
diff --git a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm index 2855e87..8b09756b 100644 --- a/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm +++ b/chrome/browser/ui/cocoa/browser_window_fullscreen_transition.mm
@@ -359,7 +359,7 @@ NSRect relativeContentFinalFrame = NSMakeRect(contentViewOrigin.x, contentViewOrigin.y, finalFrame_.size.width, finalFrame_.size.height); - [primaryWindow_ forceContentViewFrame:relativeContentFinalFrame]; + [[primaryWindow_ contentView] setFrame:relativeContentFinalFrame]; fullscreenTabStripBackgroundView_.reset( [[FullscreenTabStripBackgroundView alloc]
diff --git a/chrome/browser/ui/cocoa/chrome_browser_window.h b/chrome/browser/ui/cocoa/chrome_browser_window.h index c4667b12..2974f34d 100644 --- a/chrome/browser/ui/cocoa/chrome_browser_window.h +++ b/chrome/browser/ui/cocoa/chrome_browser_window.h
@@ -5,10 +5,10 @@ #ifndef CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_ #define CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_ -#import "chrome/browser/ui/cocoa/full_size_content_window.h" +#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h" // Common base class for chrome browser windows. -@interface ChromeBrowserWindow : FullSizeContentWindow +@interface ChromeBrowserWindow : ChromeEventProcessingWindow @end #endif // CHROME_BROWSER_UI_COCOA_CHROME_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/custom_frame_view.h b/chrome/browser/ui/cocoa/custom_frame_view.h deleted file mode 100644 index 0f87124..0000000 --- a/chrome/browser/ui/cocoa/custom_frame_view.h +++ /dev/null
@@ -1,26 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_CUSTOM_FRAME_VIEW_H_ -#define CHROME_BROWSER_UI_COCOA_CUSTOM_FRAME_VIEW_H_ - -#import <Cocoa/Cocoa.h> - -// CustomFrameView is a class whose methods we swizzle into NSGrayFrame -// on 10.7 and below, or NSThemeFrame on 10.8 and above, so that we can -// support custom frame drawing. -// This class is never to be instantiated on its own. - -@interface NSView (CustomFrameView) - -// Returns where the fullscreen button's origin should be positioned in window -// coordinates. -// We swizzle NSThemeFrame's implementation to center it vertically in the -// tabstrip (if there is a tabstrip), and to shift it to the left of the -// old-style avatar icon if necessary. -- (NSPoint)_fullScreenButtonOrigin; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_CUSTOM_FRAME_VIEW_H_
diff --git a/chrome/browser/ui/cocoa/custom_frame_view.mm b/chrome/browser/ui/cocoa/custom_frame_view.mm deleted file mode 100644 index e5bcefc..0000000 --- a/chrome/browser/ui/cocoa/custom_frame_view.mm +++ /dev/null
@@ -1,111 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/custom_frame_view.h" - -#import <Carbon/Carbon.h> -#include <crt_externs.h> -#import <objc/runtime.h> -#include <string.h> - -#include "base/logging.h" -#include "base/mac/mac_util.h" -#include "base/mac/scoped_nsautorelease_pool.h" - -@interface NSView (Swizzles) -- (NSPoint)_fullScreenButtonOriginOriginal; -@end - -@interface NSWindow (FramedBrowserWindow) -- (NSPoint)fullScreenButtonOriginAdjustment; -@end - -@interface CustomFrameView : NSView - -// Clang emits a warning if designated initializers don't call the super -// initializer, even if the method raises an exception. -// http://www.crbug.com/479019. -- (id)initWithFrame:(NSRect)frame UNAVAILABLE_ATTRIBUTE; -- (id)initWithCoder:(NSCoder*)coder UNAVAILABLE_ATTRIBUTE; - -@end - -@implementation CustomFrameView - -+ (void)load { - // Swizzling should only happen in the browser process. Interacting with - // AppKit will run +[borderViewClass initialize] in the renderer, which - // may establish Mach IPC with com.apple.windowserver. - // Note that CommandLine has not been initialized yet, since this is running - // as a module initializer. - const char* const* const argv = *_NSGetArgv(); - const int argc = *_NSGetArgc(); - const char kType[] = "--type="; - for (int i = 1; i < argc; ++i) { - const char* arg = argv[i]; - if (strncmp(arg, kType, strlen(kType)) == 0) - return; - } - - // In Yosemite, the fullscreen button replaces the zoom button. We no longer - // need to swizzle out this AppKit private method. - if (!base::mac::IsOS10_9()) - return; - - base::mac::ScopedNSAutoreleasePool pool; - - // On 10.8+ the background for textured windows are no longer drawn by - // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>. - Class borderViewClass = NSClassFromString(@"NSThemeFrame"); - DCHECK(borderViewClass); - if (!borderViewClass) return; - - // Swizzle the method that sets the origin for the Lion fullscreen button. - // Do nothing if it cannot be found. - Method m0 = class_getInstanceMethod([self class], - @selector(_fullScreenButtonOrigin)); - if (m0) { - BOOL didAdd = class_addMethod(borderViewClass, - @selector(_fullScreenButtonOriginOriginal), - method_getImplementation(m0), - method_getTypeEncoding(m0)); - if (didAdd) { - Method m1 = class_getInstanceMethod(borderViewClass, - @selector(_fullScreenButtonOrigin)); - Method m2 = class_getInstanceMethod( - borderViewClass, @selector(_fullScreenButtonOriginOriginal)); - if (m1 && m2) { - method_exchangeImplementations(m1, m2); - } - } - } -} - -- (id)initWithFrame:(NSRect)frame { - // This class is not for instantiating. - [self doesNotRecognizeSelector:_cmd]; - return nil; -} - -- (id)initWithCoder:(NSCoder*)coder { - // This class is not for instantiating. - [self doesNotRecognizeSelector:_cmd]; - return nil; -} - -// Override to move the fullscreen button to the left of the profile avatar. -- (NSPoint)_fullScreenButtonOrigin { - NSWindow* window = [self window]; - NSPoint offset = NSZeroPoint; - - if ([window respondsToSelector:@selector(fullScreenButtonOriginAdjustment)]) - offset = [window fullScreenButtonOriginAdjustment]; - - NSPoint origin = [self _fullScreenButtonOriginOriginal]; - origin.x += offset.x; - origin.y += offset.y; - return origin; -} - -@end
diff --git a/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm b/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm deleted file mode 100644 index 33339ad..0000000 --- a/chrome/browser/ui/cocoa/custom_frame_view_unittest.mm +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import <Cocoa/Cocoa.h> -#include <objc/runtime.h> - -#include "base/mac/mac_util.h" -#include "base/mac/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/custom_frame_view.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -class CustomFrameViewTest : public PlatformTest { - public: - CustomFrameViewTest() { - NSRect frame = NSMakeRect(0, 0, 50, 50); - // We create NSGrayFrame instead of CustomFrameView because - // we are swizzling into NSThemeFrame. - Class customFrameClass = NSClassFromString(@"NSThemeFrame"); - view_.reset([[customFrameClass alloc] initWithFrame:frame]); - } - - base::scoped_nsobject<NSView> view_; -}; - -// Test to make sure our class modifications were successful. -TEST_F(CustomFrameViewTest, SuccessfulClassModifications) { - // In Yosemite, the fullscreen button replaces the zoom button. We no longer - // need to swizzle out this AppKit private method. - if (!base::mac::IsOS10_9()) - return; - - unsigned int count; - BOOL foundSwizzledMethod = NO; - - Method* methods = class_copyMethodList([view_ class], &count); - for (unsigned int i = 0; i < count; ++i) { - SEL selector = method_getName(methods[i]); - if (selector == @selector(_fullScreenButtonOriginOriginal)) - foundSwizzledMethod = YES; - } - EXPECT_TRUE(foundSwizzledMethod); - free(methods); -}
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.h b/chrome/browser/ui/cocoa/framed_browser_window.h index 6acd269..2488946 100644 --- a/chrome/browser/ui/cocoa/framed_browser_window.h +++ b/chrome/browser/ui/cocoa/framed_browser_window.h
@@ -9,16 +9,6 @@ #include "chrome/browser/ui/cocoa/chrome_browser_window.h" -// Offsets from the top/left of the window frame to the top of the window -// controls (zoom, close, miniaturize) for a window with a tabstrip. -const NSInteger kFramedWindowButtonsWithTabStripOffsetFromTop = 11; -const NSInteger kFramedWindowButtonsWithTabStripOffsetFromLeft = 11; - -// Offsets from the top/left of the window frame to the top of the window -// controls (zoom, close, miniaturize) for a window without a tabstrip. -const NSInteger kFramedWindowButtonsWithoutTabStripOffsetFromTop = 3; -const NSInteger kFramedWindowButtonsWithoutTabStripOffsetFromLeft = 7; - // Cocoa class representing a framed browser window. // We need to override NSWindow with our own class since we need access to all // unhandled keyboard events and subclassing NSWindow is the only method to do @@ -26,25 +16,26 @@ @interface FramedBrowserWindow : ChromeBrowserWindow { @private BOOL shouldHideTitle_; - BOOL hasTabStrip_; - NSButton* closeButton_; - NSButton* miniaturizeButton_; - NSButton* zoomButton_; // Locks the window's frame and style mask. If it's set to YES, then the // frame and the style mask cannot be changed. BOOL styleMaskLock_; - - CGFloat windowButtonsInterButtonSpacing_; } // The amount of window background image that is painted at the top of the // window, so that it shows behind the tap strip area. + (CGFloat)browserFrameViewPaintHeight; -// Designated initializer. -- (id)initWithContentRect:(NSRect)contentRect - hasTabStrip:(BOOL)hasTabStrip; +// The style mask which -initWithContentRect: will use to create the window. +// May be overridden by subclasses. ++ (NSUInteger)defaultStyleMask; + +- (id)initWithContentRect:(NSRect)contentRect NS_DESIGNATED_INITIALIZER; + +- (instancetype)initWithContentRect:(NSRect)contentRect + styleMask:(NSWindowStyleMask)style + backing:(NSBackingStoreType)bufferingType + defer:(BOOL)flag NS_UNAVAILABLE; // Tells the window to suppress title drawing. - (void)setShouldHideTitle:(BOOL)flag; @@ -59,13 +50,6 @@ // when frameAndStyleMaskLock_ is set to true. - (void)setStyleMask:(NSUInteger)styleMask; -// Returns the desired spacing between window control views. -- (CGFloat)windowButtonsInterButtonSpacing; - -// Called by CustomFrameView to determine a custom location for the Lion -// fullscreen button. Returns NSZeroPoint to use the Lion default. -- (NSPoint)fullScreenButtonOriginAdjustment; - // Draws the window theme into the specified rect. Returns whether a theme was // drawn (whether incognito or full pattern theme; an overlay image doesn't // count).
diff --git a/chrome/browser/ui/cocoa/framed_browser_window.mm b/chrome/browser/ui/cocoa/framed_browser_window.mm index acd5343..6a1cff36 100644 --- a/chrome/browser/ui/cocoa/framed_browser_window.mm +++ b/chrome/browser/ui/cocoa/framed_browser_window.mm
@@ -20,7 +20,6 @@ #import "chrome/browser/ui/cocoa/browser_window_touch_bar.h" #import "chrome/browser/ui/cocoa/browser_window_utils.h" #include "chrome/browser/ui/cocoa/l10n_util.h" -#import "chrome/browser/ui/cocoa/tabs/tab_strip_controller.h" #import "chrome/browser/ui/cocoa/themed_window.h" #include "chrome/grit/theme_resources.h" #include "ui/base/cocoa/cocoa_base_utils.h" @@ -28,63 +27,8 @@ #import "ui/base/cocoa/nsview_additions.h" #import "ui/base/cocoa/touch_bar_forward_declarations.h" -// Implementer's note: Moving the window controls is tricky. When altering the -// code, ensure that: -// - accessibility hit testing works -// - the accessibility hierarchy is correct -// - close/min in the background don't bring the window forward -// - rollover effects work correctly - -// The NSLayoutConstraint class hierarchy only exists in the 10.11 SDK. When -// targeting something lower, constraintEqualToAnchor:constant: needs to be -// invoked using duck typing. -#if !defined(MAC_OS_X_VERSION_10_11) || \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 -@interface NSObject (NSLayoutConstraint) -- (NSLayoutConstraint*)constraintEqualToAnchor:(id)anchor constant:(CGFloat)c; -- (NSLayoutConstraint*)constraintEqualToAnchor:(id)anchor; -@end -#endif - -namespace { - -// Size of the gradient. Empirically determined so that the gradient looks -// like what the heuristic does when there are just a few tabs. -const CGFloat kWindowGradientHeight = 24.0; - -} - -@interface FramedBrowserWindow (Private) - -// Updates the title bar's frame so it moves the windows buttons to correct -// location (frame bottom is moved down so the buttons are moved down as well). -- (void)adjustTitlebarContainer:(NSView*)titlebarContainer; -// Adds layout constraints to window buttons, respecting flag returned by -// |ShouldFlipWindowControlsInRTL| method. -- (void)setWindowButtonsConstraints; -// Replaces -[NSThemeFrame addTrackingArea:] with implementation that ignores -// tracking rect if its size is the same as the size of window buttons rect -// (rect where close, miniaturize and zoom buttons are located). This is -// needed to workaround macOS bug (rdar://28535344) which unnecessarily adds -// window buttons tracking rect even if those buttons were moved. -// TODO(crbug.com/651287): Remove this workaround once macOS bug is fixed. -- (void)forbidAddingWindowButtonsTrackingArea; -// Called when titlebar container changes its frame. This method adjusts -// titlebar container with correct frame. -- (void)titlebarDidChangeFrameNotification:(NSNotification*)notification; -// Adds layout constraints to the given window button so it displayed at correct -// location. This respects flag returned by |ShouldFlipWindowControlsInRTL| -// method. -- (void)setLeadingOffset:(CGFloat)leadingOffset - toButton:(NSWindowButton)buttonType; - -- (void)adjustCloseButton:(NSNotification*)notification; -- (void)adjustMiniaturizeButton:(NSNotification*)notification; -- (void)adjustZoomButton:(NSNotification*)notification; -- (void)adjustButton:(NSButton*)button - ofKind:(NSWindowButton)kind; +@interface FramedBrowserWindow () - (void)childWindowsDidChange; - @end @implementation FramedBrowserWindow @@ -94,99 +38,26 @@ : 60.0; } ++ (NSUInteger)defaultStyleMask { + return NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSResizableWindowMask | + NSTexturedBackgroundWindowMask; +} + - (void)setStyleMask:(NSUInteger)styleMask { if (styleMaskLock_) return; [super setStyleMask:styleMask]; } -- (id)initWithContentRect:(NSRect)contentRect - hasTabStrip:(BOOL)hasTabStrip{ - NSUInteger styleMask = NSTitledWindowMask | - NSClosableWindowMask | - NSMiniaturizableWindowMask | - NSResizableWindowMask | - NSTexturedBackgroundWindowMask; - bool shouldUseFullSizeContentView = - chrome::ShouldUseFullSizeContentView() && hasTabStrip; - if (shouldUseFullSizeContentView) { - if (@available(macOS 10.10, *)) { - styleMask |= NSFullSizeContentViewWindowMask; - } - } - +- (id)initWithContentRect:(NSRect)contentRect { if ((self = [super initWithContentRect:contentRect - styleMask:styleMask + styleMask:[[self class] defaultStyleMask] backing:NSBackingStoreBuffered - defer:YES - wantsViewsOverTitlebar:hasTabStrip])) { + defer:YES])) { // The 10.6 fullscreen code copies the title to a different window, which // will assert if it's nil. [self setTitle:@""]; - - // The following two calls fix http://crbug.com/25684 by preventing the - // window from recalculating the border thickness as the window is - // resized. - // This was causing the window tint to change for the default system theme - // when the window was being resized. - [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; - [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge]; - - hasTabStrip_ = hasTabStrip; - closeButton_ = [self standardWindowButton:NSWindowCloseButton]; - miniaturizeButton_ = [self standardWindowButton:NSWindowMiniaturizeButton]; - zoomButton_ = [self standardWindowButton:NSWindowZoomButton]; - - windowButtonsInterButtonSpacing_ = - NSMinX([miniaturizeButton_ frame]) - NSMaxX([closeButton_ frame]); - if (windowButtonsInterButtonSpacing_ < 0) - // Sierra RTL - windowButtonsInterButtonSpacing_ = - NSMinX([miniaturizeButton_ frame]) - NSMaxX([zoomButton_ frame]); - - NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - if (shouldUseFullSizeContentView) { - // If Chrome uses full sized content view then window buttons are placed - // inside titlebar (which height is 22 points). In order to move window - // buttons down the whole toolbar should be moved down. - DCHECK(closeButton_); - NSView* titlebarContainer = [[closeButton_ superview] superview]; - [self adjustTitlebarContainer:titlebarContainer]; - [center addObserver:self - selector:@selector(titlebarDidChangeFrameNotification:) - name:NSViewFrameDidChangeNotification - object:titlebarContainer]; - // Window buttons are not movable unless their positioning is forced via - // layout constraints. - [self setWindowButtonsConstraints]; - // Remove an extra tracking rect unnecessarily added by AppKit which - // highlights the buttons on mouse enter event. That rect is added where - // buttons used to be previously. - [self forbidAddingWindowButtonsTrackingArea]; - } else if (hasTabStrip_) { - // If Chrome does not use a full sized content view then AppKit adds the - // window buttons to the root view, where they must be manually - // re-positioned. - [self adjustButton:closeButton_ ofKind:NSWindowCloseButton]; - [self adjustButton:miniaturizeButton_ ofKind:NSWindowMiniaturizeButton]; - [self adjustButton:zoomButton_ ofKind:NSWindowZoomButton]; - [closeButton_ setPostsFrameChangedNotifications:YES]; - [miniaturizeButton_ setPostsFrameChangedNotifications:YES]; - [zoomButton_ setPostsFrameChangedNotifications:YES]; - - [center addObserver:self - selector:@selector(adjustCloseButton:) - name:NSViewFrameDidChangeNotification - object:closeButton_]; - [center addObserver:self - selector:@selector(adjustMiniaturizeButton:) - name:NSViewFrameDidChangeNotification - object:miniaturizeButton_]; - [center addObserver:self - selector:@selector(adjustZoomButton:) - name:NSViewFrameDidChangeNotification - object:zoomButton_]; - } } return self; @@ -204,187 +75,6 @@ return [super windowTitlebarLayoutDirection]; } -- (void)adjustTitlebarContainer:(NSView*)titlebarContainer { - if ([self styleMask] & NSFullScreenWindowMask) - return; - - DCHECK(chrome::ShouldUseFullSizeContentView()); - DCHECK([NSStringFromClass([titlebarContainer class]) - isEqual:@"NSTitlebarContainerView"]); - - NSRect newFrame = [titlebarContainer frame]; - NSRect superviewFrame = [[titlebarContainer superview] frame]; - // Increase toolbar height to move window buttons down where they should be. - newFrame.size.height = - floor((chrome::kTabStripHeight + NSHeight([closeButton_ frame])) / 2.0); - newFrame.size.width = NSWidth(superviewFrame); - newFrame.origin.y = NSHeight(superviewFrame) - NSHeight(newFrame); - newFrame.origin.x = NSMinX(superviewFrame); - [titlebarContainer setFrame:newFrame]; -} - -- (void)setWindowButtonsConstraints { - DCHECK(chrome::ShouldUseFullSizeContentView()); - - CGFloat leadingOffset = - hasTabStrip_ ? kFramedWindowButtonsWithTabStripOffsetFromLeft - : kFramedWindowButtonsWithoutTabStripOffsetFromLeft; - [self setLeadingOffset:leadingOffset toButton:NSWindowCloseButton]; - - leadingOffset += - windowButtonsInterButtonSpacing_ + NSWidth([closeButton_ frame]); - [self setLeadingOffset:leadingOffset toButton:NSWindowMiniaturizeButton]; - - leadingOffset += - windowButtonsInterButtonSpacing_ + NSWidth([miniaturizeButton_ frame]); - [self setLeadingOffset:leadingOffset toButton:NSWindowZoomButton]; -} - -- (void)forbidAddingWindowButtonsTrackingArea { - DCHECK(chrome::ShouldUseFullSizeContentView()); - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - NSView* themeFrame = [[[closeButton_ superview] superview] superview]; - Class themeFrameClass = [themeFrame class]; - DCHECK([NSStringFromClass(themeFrameClass) isEqual:@"NSThemeFrame"]); - SEL addTrackingAreaSelector = @selector(addTrackingArea:); - Method originalMethod = - class_getInstanceMethod(themeFrameClass, addTrackingAreaSelector); - IMP originalImp = method_getImplementation(originalMethod); - NSRect windowButtonsRect = NSUnionRect( - NSUnionRect([closeButton_ frame], [miniaturizeButton_ frame]), - [zoomButton_ frame]); - NSSize buttonsAreaSize = NSIntegralRect(windowButtonsRect).size; - - // |newImp| is never released with |imp_removeBlock|. - IMP newImp = imp_implementationWithBlock(^(id self, id area) { - // There is no other way to ensure that |area| is responsible for buttons - // highlighting except by relying on its size. - if (!NSEqualSizes(buttonsAreaSize, NSIntegralRect([area rect]).size)) { - originalImp(self, addTrackingAreaSelector, area); - } - }); - - // Do not use base::mac::ScopedObjCClassSwizzler as it replaces existing - // implementation which is defined in NSView and will affect the whole app - // performance. - class_replaceMethod(themeFrameClass, addTrackingAreaSelector, newImp, - method_getTypeEncoding(originalMethod)); - }); -} - -- (void)titlebarDidChangeFrameNotification:(NSNotification*)notification { - [self adjustTitlebarContainer:[notification object]]; -} - -- (void)setLeadingOffset:(CGFloat)leadingOffset - toButton:(NSWindowButton)buttonType { - DCHECK(chrome::ShouldUseFullSizeContentView()); - - NSButton* button = [self standardWindowButton:buttonType]; - [button setTranslatesAutoresizingMaskIntoConstraints:NO]; - - if (@available(macOS 10.11, *)) { - // Do not use leadingAnchor because |ShouldFlipWindowControlsInRTL| - // should determine if current locale is RTL. - NSLayoutXAxisAnchor* leadingSourceAnchor = [button leftAnchor]; - NSLayoutXAxisAnchor* leadingTargetAnchor = [[button superview] leftAnchor]; - if (cocoa_l10n_util::ShouldFlipWindowControlsInRTL()) { - leadingSourceAnchor = [button rightAnchor]; - leadingTargetAnchor = [[button superview] rightAnchor]; - leadingOffset = -leadingOffset; - } - -#if !defined(MAC_OS_X_VERSION_10_11) || \ - MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_11 - id leadingSourceAnchorDuck = leadingSourceAnchor; -#else - NSLayoutXAxisAnchor* leadingSourceAnchorDuck = leadingSourceAnchor; -#endif - [[leadingSourceAnchorDuck constraintEqualToAnchor:leadingTargetAnchor - constant:leadingOffset] - setActive:YES]; - - [[[button bottomAnchor] - constraintEqualToAnchor:[[button superview] bottomAnchor]] - setActive:YES]; - } else { - NOTREACHED(); - } -} - -- (void)adjustCloseButton:(NSNotification*)notification { - [self adjustButton:[notification object] - ofKind:NSWindowCloseButton]; -} - -- (void)adjustMiniaturizeButton:(NSNotification*)notification { - [self adjustButton:[notification object] - ofKind:NSWindowMiniaturizeButton]; -} - -- (void)adjustZoomButton:(NSNotification*)notification { - [self adjustButton:[notification object] - ofKind:NSWindowZoomButton]; -} - -- (void)adjustButton:(NSButton*)button - ofKind:(NSWindowButton)kind { - NSRect buttonFrame = [button frame]; - - CGFloat xOffset = hasTabStrip_ - ? kFramedWindowButtonsWithTabStripOffsetFromLeft - : kFramedWindowButtonsWithoutTabStripOffsetFromLeft; - CGFloat yOffset = hasTabStrip_ - ? kFramedWindowButtonsWithTabStripOffsetFromTop - : kFramedWindowButtonsWithoutTabStripOffsetFromTop; - buttonFrame.origin = - NSMakePoint(xOffset, (NSHeight([self frame]) - - NSHeight(buttonFrame) - yOffset)); - - switch (kind) { - case NSWindowZoomButton: - buttonFrame.origin.x += NSWidth([miniaturizeButton_ frame]); - buttonFrame.origin.x += windowButtonsInterButtonSpacing_; - // fallthrough - case NSWindowMiniaturizeButton: - buttonFrame.origin.x += NSWidth([closeButton_ frame]); - buttonFrame.origin.x += windowButtonsInterButtonSpacing_; - // fallthrough - default: - break; - } - - if (cocoa_l10n_util::ShouldFlipWindowControlsInRTL()) { - buttonFrame.origin.x = - NSWidth([self frame]) - buttonFrame.origin.x - NSWidth([button frame]); - } - - BOOL didPost = [button postsBoundsChangedNotifications]; - [button setPostsFrameChangedNotifications:NO]; - [button setFrame:buttonFrame]; - [button setPostsFrameChangedNotifications:didPost]; -} - -// The tab strip view covers our window buttons. So we add hit testing here -// to find them properly and return them to the accessibility system. -- (id)accessibilityHitTest:(NSPoint)point { - NSPoint windowPoint = ui::ConvertPointFromScreenToWindow(self, point); - NSControl* controls[] = { closeButton_, zoomButton_, miniaturizeButton_ }; - id value = nil; - for (size_t i = 0; i < sizeof(controls) / sizeof(controls[0]); ++i) { - if (NSPointInRect(windowPoint, [controls[i] frame])) { - value = [controls[i] accessibilityHitTest:point]; - break; - } - } - if (!value) { - value = [super accessibilityHitTest:point]; - } - return value; -} - - (void)setShouldHideTitle:(BOOL)flag { shouldHideTitle_ = flag; } @@ -397,10 +87,6 @@ return shouldHideTitle_; } -- (CGFloat)windowButtonsInterButtonSpacing { - return windowButtonsInterButtonSpacing_; -} - // This method is called whenever a window is moved in order to ensure it fits // on the screen. We cannot always handle resizes without breaking, so we // prevent frame constraining in those cases. @@ -415,29 +101,6 @@ return [super constrainFrameRect:frame toScreen:screen]; } -- (NSPoint)fullScreenButtonOriginAdjustment { - if (!hasTabStrip_) - return NSZeroPoint; - - // Vertically center the button. - NSPoint origin = NSMakePoint(0, -6); - - // If there is a profile avatar icon present, shift the button over by its - // width and some padding. The new avatar button is displayed to the right - // of the fullscreen icon, so it doesn't need to be shifted. - BrowserWindowController* bwc = - base::mac::ObjCCastStrict<BrowserWindowController>( - [self windowController]); - if ([bwc shouldShowAvatar] && ![bwc shouldUseNewAvatarButton]) { - NSView* avatarButton = [[bwc avatarButtonController] view]; - origin.x = -(NSWidth([avatarButton frame]) + 3); - } else { - origin.x -= 6; - } - - return origin; -} - + (BOOL)drawWindowThemeInDirtyRect:(NSRect)dirtyRect forView:(NSView*)view bounds:(NSRect)bounds
diff --git a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm index 0ee3491..30da899 100644 --- a/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm +++ b/chrome/browser/ui/cocoa/framed_browser_window_unittest.mm
@@ -15,13 +15,6 @@ #include "testing/gtest/include/gtest/gtest.h" #import "testing/gtest_mac.h" #include "testing/platform_test.h" -#import "third_party/ocmock/OCMock/OCMock.h" - -namespace { -NSString* const kAppleTextDirectionDefaultsKey = @"AppleTextDirection"; -NSString* const kForceRTLWritingDirectionDefaultsKey = - @"NSForceRightToLeftWritingDirection"; -} // namespace class FramedBrowserWindowTest : public CocoaTest { public: @@ -29,8 +22,7 @@ CocoaTest::SetUp(); // Create a window. window_ = [[FramedBrowserWindow alloc] - initWithContentRect:NSMakeRect(0, 0, 800, 600) - hasTabStrip:YES]; + initWithContentRect:NSMakeRect(0, 0, 800, 600)]; if (base::debug::BeingDebugged()) { [window_ orderFront:nil]; } else { @@ -94,206 +86,3 @@ EXPECT_TRUE([window_ _isTitleHidden]); EXPECT_TRUE([emptyTitleData isEqualToData:hiddenTitleData]); } - -// Test to make sure that our window widgets are in the right place. -TEST_F(FramedBrowserWindowTest, WindowWidgetLocation) { - BOOL yes = YES; - BOOL no = NO; - - // First without a tabstrip. - [window_ close]; - window_ = [[FramedBrowserWindow alloc] - initWithContentRect:NSMakeRect(0, 0, 800, 600) - hasTabStrip:NO]; - // Update window layout according to existing layout constraints. - [window_ layoutIfNeeded]; - id controller = [OCMockObject mockForClass:[BrowserWindowController class]]; - [[[controller stub] andReturnValue:OCMOCK_VALUE(yes)] - isKindOfClass:[BrowserWindowController class]]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] hasTabStrip]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] hasTitleBar]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] isTabbedWindow]; - [window_ setWindowController:controller]; - - NSView* closeBoxControl = [window_ standardWindowButton:NSWindowCloseButton]; - EXPECT_TRUE(closeBoxControl); - NSRect closeBoxFrame = [closeBoxControl convertRect:[closeBoxControl bounds] - toView:nil]; - NSRect windowBounds = [window_ frame]; - windowBounds = [[window_ contentView] convertRect:windowBounds fromView:nil]; - windowBounds.origin = NSZeroPoint; - EXPECT_EQ(NSMaxY(closeBoxFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithoutTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(closeBoxFrame), - kFramedWindowButtonsWithoutTabStripOffsetFromLeft); - - NSView* miniaturizeControl = - [window_ standardWindowButton:NSWindowMiniaturizeButton]; - EXPECT_TRUE(miniaturizeControl); - NSRect miniaturizeFrame = - [miniaturizeControl convertRect:[miniaturizeControl bounds] - toView:nil]; - EXPECT_LT(NSMaxX(closeBoxFrame), NSMinX(miniaturizeFrame)); - EXPECT_EQ(NSMaxY(miniaturizeFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithoutTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(miniaturizeFrame), - NSMaxX(closeBoxFrame) + [window_ windowButtonsInterButtonSpacing]); - [window_ setWindowController:nil]; - - // Then with a tabstrip. - [window_ close]; - window_ = [[FramedBrowserWindow alloc] - initWithContentRect:NSMakeRect(0, 0, 800, 600) - hasTabStrip:YES]; - // Update window layout according to existing layout constraints. - [window_ layoutIfNeeded]; - controller = [OCMockObject mockForClass:[BrowserWindowController class]]; - [[[controller stub] andReturnValue:OCMOCK_VALUE(yes)] - isKindOfClass:[BrowserWindowController class]]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] hasTabStrip]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] hasTitleBar]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] isTabbedWindow]; - [window_ setWindowController:controller]; - - closeBoxControl = [window_ standardWindowButton:NSWindowCloseButton]; - EXPECT_TRUE(closeBoxControl); - closeBoxFrame = [closeBoxControl convertRect:[closeBoxControl bounds] - toView:nil]; - windowBounds = [window_ frame]; - windowBounds = [[window_ contentView] convertRect:windowBounds fromView:nil]; - windowBounds.origin = NSZeroPoint; - EXPECT_EQ(NSMaxY(closeBoxFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(closeBoxFrame), - kFramedWindowButtonsWithTabStripOffsetFromLeft); - - miniaturizeControl = [window_ standardWindowButton:NSWindowMiniaturizeButton]; - EXPECT_TRUE(miniaturizeControl); - miniaturizeFrame = [miniaturizeControl convertRect:[miniaturizeControl bounds] - toView:nil]; - EXPECT_EQ(NSMaxY(miniaturizeFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(miniaturizeFrame), - NSMaxX(closeBoxFrame) + [window_ windowButtonsInterButtonSpacing]); - [window_ setWindowController:nil]; -} - -class FramedBrowserWindowRTLTest : public FramedBrowserWindowTest { - void SetUp() override { - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - originalAppleTextDirection_ = - [defaults boolForKey:kAppleTextDirectionDefaultsKey]; - originalRTLWritingDirection_ = - [defaults boolForKey:kForceRTLWritingDirectionDefaultsKey]; - [defaults setBool:YES forKey:kAppleTextDirectionDefaultsKey]; - [defaults setBool:YES forKey:kForceRTLWritingDirectionDefaultsKey]; - FramedBrowserWindowTest::SetUp(); - } - - void TearDown() override { - FramedBrowserWindowTest::TearDown(); - NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; - [defaults setBool:originalAppleTextDirection_ - forKey:kAppleTextDirectionDefaultsKey]; - [defaults setBool:originalRTLWritingDirection_ - forKey:kForceRTLWritingDirectionDefaultsKey]; - } - - private: - BOOL originalAppleTextDirection_; - BOOL originalRTLWritingDirection_; -}; - -// Test to make sure that our window widgets are in the right place. -// Currently, this is the same exact test as above, since RTL button -// layout is behind the ExperimentalMacRTL flag. However, this ensures -// that our calculations are correct for Sierra RTL, which lays out -// the window buttons in reverse by default. See crbug/662079. -TEST_F(FramedBrowserWindowRTLTest, WindowWidgetLocation) { - BOOL yes = YES; - BOOL no = NO; - - // First without a tabstrip. - [window_ close]; - window_ = [[FramedBrowserWindow alloc] - initWithContentRect:NSMakeRect(0, 0, 800, 600) - hasTabStrip:NO]; - // Update window layout according to existing layout constraints. - [window_ layoutIfNeeded]; - id controller = [OCMockObject mockForClass:[BrowserWindowController class]]; - [[[controller stub] andReturnValue:OCMOCK_VALUE(yes)] - isKindOfClass:[BrowserWindowController class]]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] hasTabStrip]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] hasTitleBar]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] isTabbedWindow]; - [window_ setWindowController:controller]; - - NSView* closeBoxControl = [window_ standardWindowButton:NSWindowCloseButton]; - EXPECT_TRUE(closeBoxControl); - NSRect closeBoxFrame = - [closeBoxControl convertRect:[closeBoxControl bounds] toView:nil]; - NSRect windowBounds = [window_ frame]; - windowBounds = [[window_ contentView] convertRect:windowBounds fromView:nil]; - windowBounds.origin = NSZeroPoint; - EXPECT_EQ( - NSMaxY(closeBoxFrame), - NSMaxY(windowBounds) - kFramedWindowButtonsWithoutTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(closeBoxFrame), - kFramedWindowButtonsWithoutTabStripOffsetFromLeft); - - NSView* miniaturizeControl = - [window_ standardWindowButton:NSWindowMiniaturizeButton]; - EXPECT_TRUE(miniaturizeControl); - NSRect miniaturizeFrame = - [miniaturizeControl convertRect:[miniaturizeControl bounds] toView:nil]; - EXPECT_LT(NSMaxX(closeBoxFrame), NSMinX(miniaturizeFrame)); - EXPECT_EQ(NSMaxY(miniaturizeFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithoutTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(miniaturizeFrame), - NSMaxX(closeBoxFrame) + [window_ windowButtonsInterButtonSpacing]); - [window_ setWindowController:nil]; - - // Then with a tabstrip. - [window_ close]; - window_ = [[FramedBrowserWindow alloc] - initWithContentRect:NSMakeRect(0, 0, 800, 600) - hasTabStrip:YES]; - // Update window layout according to existing layout constraints. - [window_ layoutIfNeeded]; - controller = [OCMockObject mockForClass:[BrowserWindowController class]]; - [[[controller stub] andReturnValue:OCMOCK_VALUE(yes)] - isKindOfClass:[BrowserWindowController class]]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] hasTabStrip]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(no)] hasTitleBar]; - [[[controller expect] andReturnValue:OCMOCK_VALUE(yes)] isTabbedWindow]; - [window_ setWindowController:controller]; - - closeBoxControl = [window_ standardWindowButton:NSWindowCloseButton]; - EXPECT_TRUE(closeBoxControl); - closeBoxFrame = [closeBoxControl convertRect:[closeBoxControl bounds] - toView:nil]; - windowBounds = [window_ frame]; - windowBounds = [[window_ contentView] convertRect:windowBounds fromView:nil]; - windowBounds.origin = NSZeroPoint; - EXPECT_EQ(NSMaxY(closeBoxFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(closeBoxFrame), - kFramedWindowButtonsWithTabStripOffsetFromLeft); - - miniaturizeControl = [window_ standardWindowButton:NSWindowMiniaturizeButton]; - EXPECT_TRUE(miniaturizeControl); - miniaturizeFrame = [miniaturizeControl convertRect:[miniaturizeControl bounds] - toView:nil]; - EXPECT_EQ(NSMaxY(miniaturizeFrame), - NSMaxY(windowBounds) - - kFramedWindowButtonsWithTabStripOffsetFromTop); - EXPECT_EQ(NSMinX(miniaturizeFrame), - NSMaxX(closeBoxFrame) + [window_ windowButtonsInterButtonSpacing]); - [window_ setWindowController:nil]; -}
diff --git a/chrome/browser/ui/cocoa/full_size_content_window.h b/chrome/browser/ui/cocoa/full_size_content_window.h deleted file mode 100644 index 078d9fb..0000000 --- a/chrome/browser/ui/cocoa/full_size_content_window.h +++ /dev/null
@@ -1,46 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_COCOA_FULL_SIZE_CONTENT_WINDOW_H_ -#define CHROME_BROWSER_UI_COCOA_FULL_SIZE_CONTENT_WINDOW_H_ - -#import "chrome/browser/ui/cocoa/chrome_event_processing_window.h" - -#include "base/mac/scoped_nsobject.h" - -// By default, the contentView does not occupy the full size of a framed -// window. Chrome still wants to draw in the title bar. Historically, Chrome -// has done this by adding subviews directly to the root view. This causes -// several problems. The most egregious is related to layer ordering when the -// root view does not have a layer. By giving the contentView the same size as -// the window, there is no longer any need to add subviews to the root view. -// -// If the window does not have a titlebar, then its contentView already has the -// same size as the window. In this case, this class has no effect. -// -// This class currently does not support changing the window's style after the -// window has been initialized. -@interface FullSizeContentWindow : ChromeEventProcessingWindow { - @private - // Holds the view that replaces [window contentView]. This view has the same - // size as the window. Empty if there is no titlebar. - base::scoped_nsobject<NSView> chromeWindowView_; -} - -// Designated initializer. -- (instancetype)initWithContentRect:(NSRect)contentRect - styleMask:(NSUInteger)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation - wantsViewsOverTitlebar:(BOOL)wantsViewsOverTitlebar; - -// Forces |chromeWindowView_| to resize to the given size. This need to be -// forced because by default, the contentView will always have the same size -// as the window. If |chromeWindowView_| is empty, we will set the frame of -// [window contentView] to the given frame. -- (void)forceContentViewFrame:(NSRect)frame; - -@end - -#endif // CHROME_BROWSER_UI_COCOA_FULL_SIZE_CONTENT_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/full_size_content_window.mm b/chrome/browser/ui/cocoa/full_size_content_window.mm deleted file mode 100644 index 3b4c82b2..0000000 --- a/chrome/browser/ui/cocoa/full_size_content_window.mm +++ /dev/null
@@ -1,209 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#import "chrome/browser/ui/cocoa/full_size_content_window.h" - -#include <crt_externs.h> - -#include "base/auto_reset.h" -#include "base/logging.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_objc_class_swizzler.h" -#import "chrome/browser/ui/cocoa/browser_window_layout.h" - -@interface FullSizeContentWindow () - -+ (BOOL)shouldUseFullSizeContentViewForStyle:(NSUInteger)windowStyle; - -@end - -// This view always takes the size of its superview. It is intended to be used -// as a NSWindow's contentView. It is needed because NSWindow's implementation -// explicitly resizes the contentView at inopportune times. -@interface FullSizeContentView : NSView { - BOOL forceFrameFlag_; -} - -// This method allows us to set the content view size since setFrameSize is -// overridden to prevent the view from shrinking. -- (void)forceFrame:(NSRect)frame; - -@end - -@implementation FullSizeContentView - -// This method is directly called by AppKit during a live window resize. -// Override it to prevent the content view from shrinking. -- (void)setFrameSize:(NSSize)size { - if ([self superview] && !forceFrameFlag_) - size = [[self superview] bounds].size; - [super setFrameSize:size]; -} - -- (void)forceFrame:(NSRect)frame { - forceFrameFlag_ = YES; - [super setFrame:frame]; - forceFrameFlag_ = NO; -} - -@end - -static bool g_disable_callstacksymbols = false; -static IMP g_original_callstacksymbols_implementation; - -@interface FullSizeContentWindowSwizzlingSupport : NSObject -@end - -@implementation FullSizeContentWindowSwizzlingSupport - -// This method replaces [NSThread callStackSymbols] via swizzling - see +load -// below. -+ (NSArray*)callStackSymbols { - return g_disable_callstacksymbols ? - @[@"+callStackSymbols disabled for performance reasons"] : - g_original_callstacksymbols_implementation( - self, @selector(callStackSymbols)); -} - -@end - -@implementation FullSizeContentWindow - -#pragma mark - Lifecycle - -// In initWithContentRect:styleMask:backing:defer:, the call to -// [NSView addSubview:positioned:relativeTo:] causes NSWindow to complain that -// an unknown view is being added to it, and to generate a stack trace. -// Not only does this stack trace pollute the console, it can also take hundreds -// of milliseconds to generate (because of symbolication). By swizzling -// [NSThread callStackSymbols] we can prevent the stack trace output. -// See crbug.com/520373 . -+ (void)load { - // Swizzling should only happen in the browser process. - const char* const* const argv = *_NSGetArgv(); - const int argc = *_NSGetArgc(); - const char kType[] = "--type="; - for (int i = 1; i < argc; ++i) { - const char* arg = argv[i]; - if (strncmp(arg, kType, strlen(kType)) == 0) { - return; - } - } - - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - Class targetClass = [NSThread class]; - Class swizzleClass = [FullSizeContentWindowSwizzlingSupport class]; - SEL targetSelector = @selector(callStackSymbols); - - CR_DEFINE_STATIC_LOCAL(base::mac::ScopedObjCClassSwizzler, - callStackSymbolsSuppressor, (targetClass, - swizzleClass, targetSelector)); - g_original_callstacksymbols_implementation = - callStackSymbolsSuppressor.GetOriginalImplementation(); - }); -} - -- (instancetype)init { - NOTREACHED(); - return nil; -} - -- (instancetype)initWithContentRect:(NSRect)contentRect - styleMask:(NSUInteger)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation { - return [self initWithContentRect:contentRect - styleMask:windowStyle - backing:bufferingType - defer:deferCreation - wantsViewsOverTitlebar:NO]; -} - -- (instancetype)initWithContentRect:(NSRect)contentRect - styleMask:(NSUInteger)windowStyle - backing:(NSBackingStoreType)bufferingType - defer:(BOOL)deferCreation - wantsViewsOverTitlebar:(BOOL)wantsViewsOverTitlebar { - self = [super initWithContentRect:contentRect - styleMask:windowStyle - backing:bufferingType - defer:deferCreation]; - if (self) { - if (wantsViewsOverTitlebar && - [FullSizeContentWindow - shouldUseFullSizeContentViewForStyle:windowStyle]) { - chromeWindowView_.reset([[FullSizeContentView alloc] init]); - [chromeWindowView_ - setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; - [self setContentView:chromeWindowView_]; - [chromeWindowView_ setFrame:[[chromeWindowView_ superview] bounds]]; - - if (!chrome::ShouldUseFullSizeContentView()) { - // Chrome content view overlaps the window control buttons. Adding - // subview above the window's content view ensures that content view is - // positioned below the buttons. - NSView* superview = [chromeWindowView_ superview]; - [chromeWindowView_ removeFromSuperview]; - - // Prevent the AppKit from generating a backtrace to include in it's - // complaint about our upcoming call to - // addSubview:positioned:relativeTo:. See +load for more info. - base::AutoReset<bool> disable_symbolication(&g_disable_callstacksymbols, - true); - - [superview addSubview:chromeWindowView_ - positioned:NSWindowBelow - relativeTo:nil]; - } - } - } - return self; -} - -- (void)forceContentViewFrame:(NSRect)frame { - if ([chromeWindowView_ isKindOfClass:[FullSizeContentView class]]) { - FullSizeContentView* contentView = - base::mac::ObjCCast<FullSizeContentView>(chromeWindowView_); - [contentView forceFrame:frame]; - } else if (chromeWindowView_) { - [chromeWindowView_ setFrame:frame]; - } else { - [self.contentView setFrame:frame]; - } -} - -#pragma mark - Private Methods - -+ (BOOL)shouldUseFullSizeContentViewForStyle:(NSUInteger)windowStyle { - return windowStyle & NSTitledWindowMask; -} - -#pragma mark - NSWindow Overrides - -+ (NSRect)frameRectForContentRect:(NSRect)cRect styleMask:(NSUInteger)aStyle { - if ([self shouldUseFullSizeContentViewForStyle:aStyle]) - return cRect; - return [super frameRectForContentRect:cRect styleMask:aStyle]; -} - -- (NSRect)frameRectForContentRect:(NSRect)contentRect { - if (chromeWindowView_) - return contentRect; - return [super frameRectForContentRect:contentRect]; -} - -+ (NSRect)contentRectForFrameRect:(NSRect)fRect styleMask:(NSUInteger)aStyle { - if ([self shouldUseFullSizeContentViewForStyle:aStyle]) - return fRect; - return [super contentRectForFrameRect:fRect styleMask:aStyle]; -} - -- (NSRect)contentRectForFrameRect:(NSRect)frameRect { - if (chromeWindowView_) - return frameRect; - return [super contentRectForFrameRect:frameRect]; -} - -@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h index 11777d6..b42afba5 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.h
@@ -33,8 +33,6 @@ // Uncommon icon that only shows on answer rows (e.g. weather). @property(readonly, retain, nonatomic) NSImage* answerImage; -// The offset at which the tail suggestion contents should be displayed. -@property(readonly, nonatomic) CGFloat contentsOffset; @property(readonly, nonatomic) BOOL isContentsRTL; // Is this suggestion an answer or calculator result. @@ -43,7 +41,6 @@ @property(readonly, nonatomic) int maxLines; - (instancetype)initWithMatch:(const AutocompleteMatch&)match - contentsOffset:(CGFloat)contentsOffset image:(NSImage*)image answerImage:(NSImage*)answerImage forDarkTheme:(BOOL)isDarkTheme;
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm index 6f69d19..fd7cc66 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell.mm
@@ -366,10 +366,6 @@ origin:(NSPoint)origin withMaxWidth:(int)maxWidth forDarkTheme:(BOOL)isDarkTheme; -- (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame - tableView:(OmniboxPopupMatrix*)tableView - withContentsMaxWidth:(int*)contentsMaxWidth - forDarkTheme:(BOOL)isDarkTheme; - (void)drawMatchWithFrame:(NSRect)cellFrame inView:(NSView*)controlView; @end @@ -381,21 +377,18 @@ @synthesize image = image_; @synthesize incognitoImage = incognitoImage_; @synthesize answerImage = answerImage_; -@synthesize contentsOffset = contentsOffset_; @synthesize isContentsRTL = isContentsRTL_; @synthesize isAnswer = isAnswer_; @synthesize matchType = matchType_; @synthesize maxLines = maxLines_; - (instancetype)initWithMatch:(const AutocompleteMatch&)match - contentsOffset:(CGFloat)contentsOffset image:(NSImage*)image answerImage:(NSImage*)answerImage forDarkTheme:(BOOL)isDarkTheme { if ((self = [super init])) { image_ = [image retain]; answerImage_ = [answerImage retain]; - contentsOffset_ = contentsOffset; isContentsRTL_ = (base::i18n::RIGHT_TO_LEFT == @@ -523,14 +516,6 @@ if (isVerticalLayout && descriptionMaxWidth == 0) origin.y += halfLineHeight; - if ([cellData matchType] == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { - // Tail suggestions are rendered with a prefix (usually ellipsis), which - // appear vertically stacked. - origin.x += [self drawMatchPrefixWithFrame:cellFrame - tableView:tableView - withContentsMaxWidth:&contentsMaxWidth - forDarkTheme:isDarkTheme]; - } origin.x += [self drawMatchPart:[cellData contents] withFrame:cellFrame origin:origin @@ -579,54 +564,6 @@ } } -- (CGFloat)drawMatchPrefixWithFrame:(NSRect)cellFrame - tableView:(OmniboxPopupMatrix*)tableView - withContentsMaxWidth:(int*)contentsMaxWidth - forDarkTheme:(BOOL)isDarkTheme { - OmniboxPopupCellData* cellData = - base::mac::ObjCCastStrict<OmniboxPopupCellData>([self objectValue]); - CGFloat offset = 0.0f; - CGFloat remainingWidth = - [OmniboxPopupCell getTextContentAreaWidth:[tableView contentMaxWidth]]; - CGFloat prefixWidth = [[cellData prefix] size].width; - - CGFloat prefixOffset = 0.0f; - if (base::i18n::IsRTL() != [cellData isContentsRTL]) { - // The contents is rendered between the contents offset extending towards - // the start edge, while prefix is rendered in opposite direction. Ideally - // the prefix should be rendered at |contentsOffset_|. If that is not - // sufficient to render the widest suggestion, we increase it to - // |maxMatchContentsWidth|. If |remainingWidth| is not sufficient to - // accommodate that, we reduce the offset so that the prefix gets rendered. - prefixOffset = std::min( - remainingWidth - prefixWidth, - std::max([cellData contentsOffset], [tableView maxMatchContentsWidth])); - offset = std::max<CGFloat>(0.0, prefixOffset - *contentsMaxWidth); - } else { // The direction of contents is same as UI direction. - // Ideally the offset should be |contentsOffset_|. If the max total width - // (|prefixWidth| + |maxMatchContentsWidth|) from offset will exceed the - // |remainingWidth|, then we shift the offset to the left , so that all - // tail suggestions are visible. - // We have to render the prefix, so offset has to be at least |prefixWidth|. - offset = - std::max(prefixWidth, - std::min(remainingWidth - [tableView maxMatchContentsWidth], - [cellData contentsOffset])); - prefixOffset = offset - prefixWidth; - } - *contentsMaxWidth = std::min((int)ceilf(remainingWidth - prefixWidth), - *contentsMaxWidth); - NSPoint origin = NSMakePoint( - prefixOffset + kMaterialTextStartOffset + [tableView contentLeftPadding], - 0); - [self drawMatchPart:[cellData prefix] - withFrame:cellFrame - origin:origin - withMaxWidth:prefixWidth - forDarkTheme:isDarkTheme]; - return offset; -} - - (CGFloat)drawMatchPart:(NSAttributedString*)attributedString withFrame:(NSRect)cellFrame origin:(NSPoint)origin
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm index 88eb7cd..77d6d340 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_cell_unittest.mm
@@ -44,7 +44,6 @@ AutocompleteMatch match; cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - contentsOffset:0 image:[NSImage imageNamed:NSImageNameInfo] answerImage:nil forDarkTheme:NO]); @@ -57,7 +56,6 @@ match.contents = base::ASCIIToUTF16("The quick brown fox jumps over the lazy dog."); cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - contentsOffset:0 image:nil answerImage:nil forDarkTheme:NO]); @@ -84,7 +82,6 @@ match.answer = SuggestionAnswer::ParseAnswer(dictionary); EXPECT_TRUE(match.answer); cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - contentsOffset:0 image:nil answerImage:nil forDarkTheme:NO]); @@ -141,7 +138,6 @@ match.answer = SuggestionAnswer::ParseAnswer(dictionary); EXPECT_TRUE(match.answer); cellData_.reset([[OmniboxPopupCellData alloc] initWithMatch:match - contentsOffset:0 image:nil answerImage:nil forDarkTheme:NO]);
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm index 93ec8a7..0b70e65 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_matrix.mm
@@ -35,29 +35,18 @@ answerImage:(NSImage*)answerImage { base::scoped_nsobject<NSMutableArray> array([[NSMutableArray alloc] init]); BOOL isDarkTheme = [tableView hasDarkTheme]; - CGFloat maxMatchContentsWidth = 0.0f; - CGFloat contentsOffset = -1.0f; for (const AutocompleteMatch& match : result) { - if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL && - contentsOffset < 0.0f) - contentsOffset = [OmniboxPopupCell computeContentsOffset:match]; base::scoped_nsobject<OmniboxPopupCellData> cellData( [[OmniboxPopupCellData alloc] initWithMatch:match - contentsOffset:contentsOffset image:popupView.ImageForMatch(match) answerImage:(match.answer ? answerImage : nil) forDarkTheme:isDarkTheme]); if (isDarkTheme) [cellData setIncognitoImage:popupView.ImageForMatch(match)]; [array addObject:cellData]; - if (match.type == AutocompleteMatchType::SEARCH_SUGGEST_TAIL) { - maxMatchContentsWidth = - std::max(maxMatchContentsWidth, [cellData getMatchContentsWidth]); - } } - [tableView setMaxMatchContentsWidth:maxMatchContentsWidth]; return [self initWithArray:array]; }
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm index be6646d4..3b0ab4d2 100644 --- a/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm +++ b/chrome/browser/ui/cocoa/omnibox/omnibox_popup_view_mac.mm
@@ -87,6 +87,7 @@ void OmniboxPopupViewMac::UpdatePopupAppearance() { DCHECK([NSThread isMainThread]); + model_->autocomplete_controller()->InlineTailPrefixes(); const AutocompleteResult& result = GetResult(); const size_t rows = result.size(); if (rows == 0) {
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window.h b/chrome/browser/ui/cocoa/tabbed_browser_window.h new file mode 100644 index 0000000..f1d11b2 --- /dev/null +++ b/chrome/browser/ui/cocoa/tabbed_browser_window.h
@@ -0,0 +1,16 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_TABBED_BROWSER_WINDOW_H_ +#define CHROME_BROWSER_UI_COCOA_TABBED_BROWSER_WINDOW_H_ + +#import <AppKit/AppKit.h> + +#include "chrome/browser/ui/cocoa/framed_browser_window.h" + +// Represents a browser window with tabs and customized window controls. +@interface TabbedBrowserWindow : FramedBrowserWindow +@end + +#endif // CHROME_BROWSER_UI_COCOA_TABBED_BROWSER_WINDOW_H_
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window.mm b/chrome/browser/ui/cocoa/tabbed_browser_window.mm new file mode 100644 index 0000000..ce42d44 --- /dev/null +++ b/chrome/browser/ui/cocoa/tabbed_browser_window.mm
@@ -0,0 +1,207 @@ +// 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. + +#import "chrome/browser/ui/cocoa/tabbed_browser_window.h" + +#import "chrome/browser/ui/cocoa/browser_window_controller.h" +#import "chrome/browser/ui/cocoa/browser_window_layout.h" + +// Implementer's note: Moving the window controls is tricky. When altering the +// code, ensure that: +// - accessibility hit testing works +// - the accessibility hierarchy is correct +// - close/min in the background don't bring the window forward +// - rollover effects work correctly + +namespace { +// Size of the gradient. Empirically determined so that the gradient looks +// like what the heuristic does when there are just a few tabs. +constexpr CGFloat kWindowGradientHeight = 24.0; + +// Offsets from the bottom/left of the titlebar to the bottom/left of the +// window buttons (zoom, close, miniaturize). +constexpr NSInteger kWindowButtonsOffsetFromBottom = 9; +constexpr NSInteger kWindowButtonsOffsetFromLeft = 11; + +// Offset from the top/right of the window to the Mavericks full screen button. +constexpr NSInteger kFullScreenButtonOffset = 9; +} // namespace + +@interface TabbedBrowserWindow () +- (CGFloat)fullScreenButtonOriginAdjustment; +@end + +// Weak so that Chrome will launch if a future macOS doesn't have NSThemeFrame. +WEAK_IMPORT_ATTRIBUTE +@interface NSThemeFrame : NSView +- (NSView*)fullScreenButton + __attribute__((availability(macos, obsoleted = 10.10))); +@end + +@interface NSWindow (PrivateAPI) ++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle; +@end + +@interface NSWindow (TenTwelveSDK) +@property(readonly) + NSUserInterfaceLayoutDirection windowTitlebarLayoutDirection; +@end + +@interface TabbedBrowserWindowFrame : NSThemeFrame +@end + +@implementation TabbedBrowserWindowFrame + +// NSThemeFrame overrides. + +- (CGFloat)_minXTitlebarWidgetInset { + return kWindowButtonsOffsetFromLeft; +} + +- (CGFloat)_minYTitlebarButtonsOffset { + return -kWindowButtonsOffsetFromBottom; +} + +- (CGFloat)_titlebarHeight { + return chrome::kTabStripHeight; +} + +// AppKit's implementation only returns YES if [self class] == [NSThemeFrame +// class]. TabbedBrowserWindowFrame could override -class to return that, but +// then -[NSWindow setStyleMask:] would recreate the frame view each time the +// style mask is touched because it wouldn't match the return value of +// +[TabbedBrowserWindow frameViewClassForStyleMask:]. +- (BOOL)_shouldFlipTrafficLightsForRTL API_AVAILABLE(macos(10.12)) { + return [[self window] windowTitlebarLayoutDirection] == + NSUserInterfaceLayoutDirectionRightToLeft; +} + +@end + +// By default, contentView does not occupy the full size of a titled window, +// and Chrome wants to draw in the title bar. Historically, Chrome did this by +// adding subviews directly to the root view. This causes several problems. The +// most egregious is related to layer ordering when the root view does not have +// a layer. By giving the contentView the same size as the window, there is no +// need to add subviews to the root view. +// +// TODO(sdy): This can be deleted once ShouldUseFullSizeContentView is +// perma-on. See https://crbug.com/605219. +@interface FullSizeTabbedBrowserWindowFrame : TabbedBrowserWindowFrame +@end + +@implementation FullSizeTabbedBrowserWindowFrame + ++ (CGRect)contentRectForFrameRect:(CGRect)frameRect + styleMask:(NSUInteger)style { + return frameRect; +} + ++ (CGRect)frameRectForContentRect:(CGRect)contentRect + styleMask:(NSUInteger)style { + return contentRect; +} + +- (CGRect)contentRectForFrameRect:(CGRect)frameRect + styleMask:(NSUInteger)style { + return frameRect; +} + +- (CGRect)frameRectForContentRect:(CGRect)contentRect + styleMask:(NSUInteger)style { + return contentRect; +} + +@end + +@interface MavericksTabbedBrowserWindowFrame : FullSizeTabbedBrowserWindowFrame +@end + +@implementation MavericksTabbedBrowserWindowFrame + +// 10.10+ has no separate fullscreen button. +- (NSPoint)_fullScreenButtonOrigin + __attribute__((availability(macos, obsoleted = 10.10))) { + CGFloat xAdjustment = [static_cast<TabbedBrowserWindow*>(self.window) + fullScreenButtonOriginAdjustment]; + NSSize fullScreenButtonSize = [self fullScreenButton].frame.size; + return NSMakePoint(NSMaxX(self.bounds) - fullScreenButtonSize.width - + kFullScreenButtonOffset - xAdjustment, + NSMaxY(self.bounds) - fullScreenButtonSize.height - + kFullScreenButtonOffset); +} + +// 10.10+ adds the content view below the window controls by default. +- (void)_setContentView:(NSView*)contentView { + [self addSubview:contentView positioned:NSWindowBelow relativeTo:nil]; +} + +@end + +@implementation TabbedBrowserWindow + +// FramedBrowserWindow overrides. + ++ (NSUInteger)defaultStyleMask { + NSUInteger styleMask = [super defaultStyleMask]; + if (chrome::ShouldUseFullSizeContentView()) { + if (@available(macOS 10.10, *)) + styleMask |= NSFullSizeContentViewWindowMask; + } + return styleMask; +} + +// NSWindow (PrivateAPI) overrides. + ++ (Class)frameViewClassForStyleMask:(NSUInteger)windowStyle { + // Because NSThemeFrame is imported weakly, if it's not present at runtime + // then it and its subclasses will be nil. + if ([TabbedBrowserWindowFrame class]) { + if (@available(macOS 10.10, *)) { + return chrome::ShouldUseFullSizeContentView() + ? [TabbedBrowserWindowFrame class] + : [FullSizeTabbedBrowserWindowFrame class]; + } + return [MavericksTabbedBrowserWindowFrame class]; + } + return [super frameViewClassForStyleMask:windowStyle]; +} + +// NSWindow's implementation of _usesCustomDrawing returns YES when the window +// has a custom frame view class, which causes several undesirable changes in +// AppKit's behavior. NSWindow subclasses in AppKit override it and return NO. +- (BOOL)_usesCustomDrawing { + return NO; +} + +// FramedBrowserWindow overrides. + +- (id)initWithContentRect:(NSRect)contentRect { + if ((self = [super initWithContentRect:contentRect])) { + // The following two calls fix http://crbug.com/25684 by preventing the + // window from recalculating the border thickness as the window is + // resized. + // This was causing the window tint to change for the default system theme + // when the window was being resized. + [self setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; + [self setContentBorderThickness:kWindowGradientHeight forEdge:NSMaxYEdge]; + } + return self; +} + +// TabbedBrowserWindow () implementation. + +- (CGFloat)fullScreenButtonOriginAdjustment { + // If there is a profile avatar icon present, shift the button over by its + // width and some padding. The new avatar button is displayed to the right + // of the fullscreen icon, so it doesn't need to be shifted. + auto* bwc = static_cast<BrowserWindowController*>([self windowController]); + if ([bwc shouldShowAvatar] && ![bwc shouldUseNewAvatarButton]) { + NSView* avatarButton = [[bwc avatarButtonController] view]; + return NSWidth([avatarButton frame]) - 3; + } + return 0; +} + +@end
diff --git a/chrome/browser/ui/cocoa/tabbed_browser_window_unittest.mm b/chrome/browser/ui/cocoa/tabbed_browser_window_unittest.mm new file mode 100644 index 0000000..e889127 --- /dev/null +++ b/chrome/browser/ui/cocoa/tabbed_browser_window_unittest.mm
@@ -0,0 +1,138 @@ +// 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. + +#import <AppKit/AppKit.h> + +#import "chrome/browser/ui/cocoa/tabbed_browser_window.h" +#import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h" + +namespace { +NSString* const kAppleTextDirectionDefaultsKey = @"AppleTextDirection"; +NSString* const kForceRTLWritingDirectionDefaultsKey = + @"NSForceRightToLeftWritingDirection"; +constexpr CGFloat kWindowButtonInset = 11; +} // namespace + +class TabbedBrowserWindowTest : public CocoaTest { + protected: + TabbedBrowserWindowTest() = default; + + void SetUp() override { + CocoaTest::SetUp(); + window_ = [[TabbedBrowserWindow alloc] + initWithContentRect:NSMakeRect(0, 0, 800, 600)]; + [window() orderBack:nil]; + } + + void TearDown() override { + [window() close]; + CocoaTest::TearDown(); + } + + TabbedBrowserWindow* window() { return window_; }; + + private: + TabbedBrowserWindow* window_; + + DISALLOW_COPY_AND_ASSIGN(TabbedBrowserWindowTest); +}; + +// Test to make sure that our window widgets are in the right place. +TEST_F(TabbedBrowserWindowTest, WindowWidgetLocation) { + NSView* closeBoxControl = [window() standardWindowButton:NSWindowCloseButton]; + EXPECT_TRUE(closeBoxControl); + NSRect closeBoxFrame = + [closeBoxControl convertRect:[closeBoxControl bounds] toView:nil]; + NSRect windowBounds = [window() frame]; + windowBounds = [[window() contentView] convertRect:windowBounds fromView:nil]; + windowBounds.origin = NSZeroPoint; + EXPECT_EQ(NSMaxY(closeBoxFrame), NSMaxY(windowBounds) - kWindowButtonInset); + EXPECT_EQ(NSMinX(closeBoxFrame), kWindowButtonInset); +} + +class TabbedBrowserWindowRTLTest : public TabbedBrowserWindowTest { + public: + TabbedBrowserWindowRTLTest() = default; + + void SetUp() override { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + originalAppleTextDirection_ = + [defaults boolForKey:kAppleTextDirectionDefaultsKey]; + originalRTLWritingDirection_ = + [defaults boolForKey:kForceRTLWritingDirectionDefaultsKey]; + [defaults setBool:YES forKey:kAppleTextDirectionDefaultsKey]; + [defaults setBool:YES forKey:kForceRTLWritingDirectionDefaultsKey]; + TabbedBrowserWindowTest::SetUp(); + } + + void TearDown() override { + TabbedBrowserWindowTest::TearDown(); + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults setBool:originalAppleTextDirection_ + forKey:kAppleTextDirectionDefaultsKey]; + [defaults setBool:originalRTLWritingDirection_ + forKey:kForceRTLWritingDirectionDefaultsKey]; + } + + private: + BOOL originalAppleTextDirection_; + BOOL originalRTLWritingDirection_; + + DISALLOW_COPY_AND_ASSIGN(TabbedBrowserWindowRTLTest); +}; + +// Test to make sure that our window widgets are in the right place. +// Currently, this is the same exact test as above, since RTL button +// layout is behind the ExperimentalMacRTL flag. However, this ensures +// that our calculations are correct for Sierra RTL, which lays out +// the window buttons in reverse by default. See crbug/662079. +TEST_F(TabbedBrowserWindowRTLTest, WindowWidgetLocation) { + NSView* closeBoxControl = [window() standardWindowButton:NSWindowCloseButton]; + EXPECT_TRUE(closeBoxControl); + NSRect closeBoxFrame = + [closeBoxControl convertRect:[closeBoxControl bounds] toView:nil]; + NSRect windowBounds = [window() frame]; + windowBounds = [[window() contentView] convertRect:windowBounds fromView:nil]; + windowBounds.origin = NSZeroPoint; + EXPECT_EQ(NSMaxY(closeBoxFrame), NSMaxY(windowBounds) - kWindowButtonInset); + EXPECT_EQ(NSMinX(closeBoxFrame), kWindowButtonInset); +} + +WEAK_IMPORT_ATTRIBUTE +@interface NSThemeFrame : NSView +@end + +// Test that NSThemeFrame and NSWindow respond to the undocumented methods +// which TabbedBrowserWindowFrame and TabbedBrowserWindow override. +TEST(TabbedBrowserWindowOverrideTest, UndocumentedMethods) { + EXPECT_TRUE([NSThemeFrame + respondsToSelector:@selector(contentRectForFrameRect:styleMask:)]); + EXPECT_TRUE([NSThemeFrame + respondsToSelector:@selector(frameRectForContentRect:styleMask:)]); + EXPECT_TRUE([NSThemeFrame + instancesRespondToSelector:@selector(_minXTitlebarWidgetInset)]); + EXPECT_TRUE([NSThemeFrame + instancesRespondToSelector:@selector(_minYTitlebarButtonsOffset)]); + EXPECT_TRUE( + [NSThemeFrame instancesRespondToSelector:@selector(_titlebarHeight)]); + EXPECT_TRUE([NSThemeFrame instancesRespondToSelector:@selector + (contentRectForFrameRect:styleMask:)]); + EXPECT_TRUE([NSThemeFrame instancesRespondToSelector:@selector + (frameRectForContentRect:styleMask:)]); + if (@available(macOS 10.12, *)) { + EXPECT_TRUE([NSThemeFrame + instancesRespondToSelector:@selector(_shouldFlipTrafficLightsForRTL)]); + } else if (@available(macOS 10.10, *)) { + } else { + EXPECT_TRUE([NSThemeFrame + instancesRespondToSelector:@selector(_fullScreenButtonOrigin)]); + EXPECT_TRUE( + [NSThemeFrame instancesRespondToSelector:@selector(_setContentView:)]); + } + + EXPECT_TRUE( + [NSWindow respondsToSelector:@selector(frameViewClassForStyleMask:)]); + EXPECT_TRUE( + [NSWindow instancesRespondToSelector:@selector(_usesCustomDrawing)]); +}
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm index 9d76445..bcec69f 100644 --- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm +++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -9,6 +9,7 @@ #import "chrome/browser/ui/cocoa/browser_window_layout.h" #import "chrome/browser/ui/cocoa/fast_resize_view.h" #import "chrome/browser/ui/cocoa/framed_browser_window.h" +#import "chrome/browser/ui/cocoa/tabbed_browser_window.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_background_view.h" #import "chrome/browser/ui/cocoa/tabs/tab_strip_view.h" #import "chrome/browser/ui/cocoa/themed_window.h" @@ -21,9 +22,7 @@ - (void)setUseOverlay:(BOOL)useOverlay; // The tab strip background view should always be inserted as the back-most -// subview of the root view. It cannot be a subview of the contentView, as that -// would cause it to become layer backed, which would cause it to draw on top -// of non-layer backed content like the window controls. +// subview of the contentView. - (void)insertTabStripBackgroundViewIntoWindow:(NSWindow*)window titleBar:(BOOL)hasTitleBar; @@ -93,8 +92,8 @@ NSRect contentRect = NSMakeRect(60, 229, kDefaultWidth, kDefaultHeight); base::scoped_nsobject<FramedBrowserWindow> window( - [[FramedBrowserWindow alloc] initWithContentRect:contentRect - hasTabStrip:hasTabStrip]); + [(hasTabStrip ? [TabbedBrowserWindow alloc] : [FramedBrowserWindow alloc]) + initWithContentRect:contentRect]); [window setReleasedWhenClosed:YES]; [window setAutorecalculatesKeyViewLoop:YES]; @@ -423,7 +422,6 @@ - (void)insertTabStripBackgroundViewIntoWindow:(NSWindow*)window titleBar:(BOOL)hasTitleBar { DCHECK(tabStripBackgroundView_); - NSView* rootView = [[window contentView] superview]; // In Material Design on 10.10 and higher, the top portion of the window is // blurred using an NSVisualEffectView. @@ -467,20 +465,18 @@ [visualEffectWrapperView addSubview:visualEffectView_]; - [chrome::ShouldUseFullSizeContentView() ? [window contentView] : rootView - addSubview:visualEffectWrapperView - positioned:NSWindowBelow - relativeTo:nil]; + [[window contentView] addSubview:visualEffectWrapperView + positioned:NSWindowBelow + relativeTo:nil]; // Make the |tabStripBackgroundView_| a child of the NSVisualEffectView. [tabStripBackgroundView_ setFrame:[visualEffectView_ bounds]]; [visualEffectView_ addSubview:tabStripBackgroundView_]; } else { DCHECK(!chrome::ShouldUseFullSizeContentView()); - [rootView addSubview:tabStripBackgroundView_ - positioned:NSWindowBelow - relativeTo:nil]; - return; + [[window contentView] addSubview:tabStripBackgroundView_ + positioned:NSWindowBelow + relativeTo:nil]; } }
diff --git a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc index 6e93bce..7b94664 100644 --- a/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_completion_status_metrics_browsertest.cc
@@ -50,17 +50,26 @@ // Complete the Payment Request. PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); - // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.PayClicked", 1, 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Completed", - 1, 1); + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_TRUE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_TRUE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_TRUE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -79,13 +88,30 @@ WaitForObservedEvent(); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_MERCHANT_NAVIGATION, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -106,13 +132,30 @@ WaitForObservedEvent(); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_MERCHANT_NAVIGATION, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -134,13 +177,30 @@ WaitForObservedEvent(); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_ABORTED_BY_MERCHANT, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -156,13 +216,30 @@ NavigateTo("/payment_request_email_test.html"); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_USER_NAVIGATION, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -178,13 +255,30 @@ ClickOnCancel(); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_ABORTED_BY_USER, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -202,13 +296,30 @@ WaitForObservedEvent(); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_ABORTED_BY_USER, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompletionStatusMetricsTest, @@ -226,13 +337,30 @@ WaitForObservedEvent(); // Make sure the metrics are logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); histogram_tester.ExpectUniqueSample( "PaymentRequest.CheckoutFunnel.Aborted", JourneyLogger::ABORT_REASON_USER_NAVIGATION, 1); + + // Make sure the correct events were logged. + std::vector<base::Bucket> buckets = + histogram_tester.GetAllSamples("PaymentRequest.Events"); + ASSERT_EQ(1U, buckets.size()); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_SHOWN); + EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_USER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_OTHER_ABORTED); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_PAY_CLICKED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_RECEIVED_INSTRUMENT_DETAILS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_SKIPPED_SHOW); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_COMPLETED); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_INITIAL_FORM_OF_PAYMENT); + EXPECT_FALSE(buckets[0].min & + JourneyLogger::EVENT_HAD_NECESSARY_COMPLETE_SUGGESTIONS); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_SHIPPING); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); } class PaymentRequestInitiatedCompletionStatusMetricsTest
diff --git a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc index 7105bf70..1a8f9dc 100644 --- a/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc +++ b/chrome/browser/ui/views/payments/payment_request_journey_logger_browsertest.cc
@@ -44,14 +44,6 @@ ResetEventObserver(DialogEvent::DIALOG_CLOSED); PayWithCreditCardAndWait(base::ASCIIToUTF16("123")); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.PayClicked", 1, 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1, 1); // Expect a credit card as the selected payment instrument in the metrics. histogram_tester.ExpectBucketCount( "PaymentRequest.SelectedPaymentMethod", @@ -77,6 +69,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } class PaymentRequestJourneyLoggerNoSupportedPaymentMethodTest @@ -101,8 +95,6 @@ ASSERT_TRUE(content::ExecuteScript(web_contents, click_buy_button_js)); WaitForObservedEvent(); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); histogram_tester.ExpectBucketCount( "PaymentRequest.CheckoutFunnel.NoShow", JourneyLogger::NOT_SHOWN_REASON_NO_SUPPORTED_PAYMENT_METHOD, 1); @@ -151,18 +143,6 @@ histogram_tester.GetAllSamples("PaymentRequest.CheckoutFunnel.NoShow") .empty()); - // Expect that other metrics were logged correctly. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.PayClicked", 1, 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1, 1); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Completed", - 1, 1); - // Make sure the correct events were logged. std::vector<base::Bucket> buckets = histogram_tester.GetAllSamples("PaymentRequest.Events"); @@ -183,6 +163,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } IN_PROC_BROWSER_TEST_F(PaymentRequestJourneyLoggerMultipleShowTest, @@ -215,19 +197,7 @@ // Complete the original Payment Request. PayWithCreditCardAndWait(base::ASCIIToUTF16("123"), first_dialog_view); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 2); - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Shown", 1, - 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.PayClicked", 1, 1); - histogram_tester.ExpectUniqueSample( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", 1, 1); - - // The metrics should show that the original Payment Request should be - // completed and the second one should not have been shown. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Completed", - 1, 1); + // There is one no show and one shown (verified below). histogram_tester.ExpectBucketCount( "PaymentRequest.CheckoutFunnel.NoShow", JourneyLogger::NOT_SHOWN_REASON_CONCURRENT_REQUESTS, 1); @@ -252,6 +222,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } class PaymentRequestJourneyLoggerAllSectionStatsTest @@ -315,6 +287,8 @@ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } // Tests that the correct number of suggestions shown for each section is logged @@ -367,6 +341,8 @@ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } class PaymentRequestJourneyLoggerNoShippingSectionStatsTest @@ -432,6 +408,8 @@ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } // Tests that the correct number of suggestions shown for each section is logged @@ -485,6 +463,8 @@ EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } class PaymentRequestJourneyLoggerNoContactDetailSectionStatsTest @@ -552,6 +532,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } // Tests that the correct number of suggestions shown for each section is logged @@ -607,6 +589,10 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } class PaymentRequestNotShownTest : public PaymentRequestBrowserTestBase { @@ -628,11 +614,6 @@ // Navigate away to abort the Payment Request and trigger the logs. NavigateTo("/payment_request_email_test.html"); - // Initiated should be logged. - histogram_tester.ExpectUniqueSample("PaymentRequest.CheckoutFunnel.Initiated", - 1, 1); - // Show should not be logged. - histogram_tester.ExpectTotalCount("PaymentRequest.CheckoutFunnel.Shown", 0); // Abort should not be logged. histogram_tester.ExpectTotalCount("PaymentRequest.CheckoutFunnel.Aborted", 0); @@ -721,6 +702,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } IN_PROC_BROWSER_TEST_F(PaymentRequestCompleteSuggestionsForEverythingTest, @@ -766,6 +749,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } IN_PROC_BROWSER_TEST_F( @@ -817,6 +802,8 @@ EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_NAME); EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_PHONE); EXPECT_TRUE(buckets[0].min & JourneyLogger::EVENT_REQUEST_PAYER_EMAIL); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_FALSE); + EXPECT_FALSE(buckets[0].min & JourneyLogger::EVENT_CAN_MAKE_PAYMENT_TRUE); } } // namespace payments
diff --git a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc index aef5d2b..09b0068 100644 --- a/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc +++ b/chrome/browser/ui/webui/offline/offline_internals_ui_message_handler.cc
@@ -206,6 +206,7 @@ offline_page->SetDouble("lastAccessTime", page.last_access_time.ToJsTime()); offline_page->SetInteger("accessCount", page.access_count); offline_page->SetString("originalUrl", page.original_url.spec()); + offline_page->SetString("requestOrigin", page.request_origin); results.Append(std::move(offline_page)); } ResolveJavascriptCallback(base::Value(callback_id), results); @@ -230,6 +231,7 @@ save_page_request->SetString("id", std::to_string(request->request_id())); save_page_request->SetString("originalUrl", request->original_url().spec()); + save_page_request->SetString("requestOrigin", request->request_origin()); save_page_requests.Append(std::move(save_page_request)); } }
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 3f389ce..4429362 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1427,6 +1427,7 @@ "../browser/sessions/persistent_tab_restore_service_browsertest.cc", "../browser/sessions/session_restore_browsertest.cc", "../browser/sessions/session_restore_browsertest_chromeos.cc", + "../browser/sessions/session_restore_observer_browsertest.cc", "../browser/sessions/tab_restore_browsertest.cc", "../browser/site_details_browsertest.cc", @@ -4633,7 +4634,6 @@ "../browser/ui/cocoa/content_settings/collected_cookies_mac_unittest.mm", "../browser/ui/cocoa/content_settings/cookie_details_unittest.mm", "../browser/ui/cocoa/content_settings/cookie_details_view_controller_unittest.mm", - "../browser/ui/cocoa/custom_frame_view_unittest.mm", "../browser/ui/cocoa/download/download_item_button_unittest.mm", "../browser/ui/cocoa/download/download_item_cell_unittest.mm", "../browser/ui/cocoa/download/download_item_controller_unittest.mm", @@ -4729,6 +4729,7 @@ "../browser/ui/cocoa/styled_text_field_cell_unittest.mm", "../browser/ui/cocoa/styled_text_field_unittest.mm", "../browser/ui/cocoa/tab_contents/sad_tab_mac_unittest.mm", + "../browser/ui/cocoa/tabbed_browser_window_unittest.mm", "../browser/ui/cocoa/tabs/alert_indicator_button_cocoa_unittest.mm", "../browser/ui/cocoa/tabs/tab_controller_unittest.mm", "../browser/ui/cocoa/tabs/tab_strip_controller_unittest.mm",
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc index d135f25a..506cb34 100644 --- a/chromecast/browser/cast_browser_main_parts.cc +++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -21,7 +21,6 @@ #include "base/threading/thread.h" #include "base/threading/thread_task_runner_handle.h" #include "build/build_config.h" -#include "cc/base/switches.h" #include "chromecast/base/cast_constants.h" #include "chromecast/base/cast_features.h" #include "chromecast/base/cast_paths.h" @@ -66,6 +65,7 @@ #include "gpu/command_buffer/service/gpu_switches.h" #include "media/base/media.h" #include "media/base/media_switches.h" +#include "ui/base/ui_base_switches.h" #include "ui/compositor/compositor_switches.h" #include "ui/gl/gl_switches.h" @@ -264,7 +264,7 @@ // TODO(halliwell): Remove after fixing b/35422666. {switches::kEnableUseZoomForDSF, "false"}, // TODO(halliwell): Revert after fix for b/63101386. - {cc::switches::kDisallowNonExactResourceReuse, ""}, + {switches::kDisallowNonExactResourceReuse, ""}, }; void AddDefaultCommandLineSwitches(base::CommandLine* command_line) {
diff --git a/components/payments/core/journey_logger.cc b/components/payments/core/journey_logger.cc index 6f6d64f0..f57b008 100644 --- a/components/payments/core/journey_logger.cc +++ b/components/payments/core/journey_logger.cc
@@ -133,13 +133,11 @@ } void JourneyLogger::SetCompleted() { - UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Completed", true); - RecordJourneyStatsHistograms(COMPLETION_STATUS_COMPLETED); } void JourneyLogger::SetAborted(AbortReason reason) { - // Don't log abort reasons if the Payment Request was triggered. + // Don't log abort reasons if the Payment Request was not triggered. if (WasPaymentRequestTriggered()) { base::UmaHistogramEnumeration("PaymentRequest.CheckoutFunnel.Aborted", reason, ABORT_REASON_MAX); @@ -155,10 +153,6 @@ void JourneyLogger::SetNotShown(NotShownReason reason) { base::UmaHistogramEnumeration("PaymentRequest.CheckoutFunnel.NoShow", reason, NOT_SHOWN_REASON_MAX); - - // Record that that Payment Request was initiated here, because nothing else - // will be recorded for a Payment Request that was not shown to the user. - UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Initiated", true); } void JourneyLogger::RecordJourneyStatsHistograms( @@ -166,7 +160,6 @@ DCHECK(!has_recorded_); has_recorded_ = true; - RecordCheckoutFlowMetrics(); RecordCanMakePaymentStats(completion_status); RecordUrlKeyedMetrics(completion_status); RecordEventsMetric(completion_status); @@ -179,23 +172,6 @@ } } -void JourneyLogger::RecordCheckoutFlowMetrics() { - UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Initiated", true); - - if (events_ & EVENT_SHOWN) - UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.Shown", true); - - if (events_ & EVENT_PAY_CLICKED) - UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.PayClicked", true); - - if (events_ & EVENT_RECEIVED_INSTRUMENT_DETAILS) - UMA_HISTOGRAM_BOOLEAN( - "PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails", true); - - if (events_ & EVENT_SKIPPED_SHOW) - UMA_HISTOGRAM_BOOLEAN("PaymentRequest.CheckoutFunnel.SkippedShow", true); -} - void JourneyLogger::RecordPaymentMethodMetric() { base::UmaHistogramEnumeration("PaymentRequest.SelectedPaymentMethod", payment_method_, SELECTED_PAYMENT_METHOD_MAX);
diff --git a/components/payments/core/journey_logger.h b/components/payments/core/journey_logger.h index bb254dae..f7665b1 100644 --- a/components/payments/core/journey_logger.h +++ b/components/payments/core/journey_logger.h
@@ -219,10 +219,6 @@ // either been completed or aborted. void RecordJourneyStatsHistograms(CompletionStatus completion_status); - // Records the histograms for all the steps of a complete checkout flow that - // were reached. - void RecordCheckoutFlowMetrics(); - // Records the metric about the selected payment method. void RecordPaymentMethodMetric();
diff --git a/components/search_provider_logos/logo_service.cc b/components/search_provider_logos/logo_service.cc index f3b6fd2..b5d98989 100644 --- a/components/search_provider_logos/logo_service.cc +++ b/components/search_provider_logos/logo_service.cc
@@ -108,13 +108,17 @@ LogoService::~LogoService() = default; void LogoService::GetLogo(search_provider_logos::LogoObserver* observer) { - if (!template_url_service_) + if (!template_url_service_) { + observer->OnObserverRemoved(); return; + } const TemplateURL* template_url = template_url_service_->GetDefaultSearchProvider(); - if (!template_url) + if (!template_url) { + observer->OnObserverRemoved(); return; + } base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); GURL logo_url; @@ -129,6 +133,7 @@ if (!template_url->url_ref().HasGoogleBaseURLs( template_url_service_->search_terms_data()) && !use_fixed_logo) { + observer->OnObserverRemoved(); return; }
diff --git a/components/viz/DEPS b/components/viz/DEPS index c4d836f..09630076 100644 --- a/components/viz/DEPS +++ b/components/viz/DEPS
@@ -1,4 +1,5 @@ include_rules = [ "-components/viz", "+components/viz/common", + "+ui/base", ]
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn index 6e3abfe..092768f 100644 --- a/components/viz/host/BUILD.gn +++ b/components/viz/host/BUILD.gn
@@ -11,6 +11,8 @@ "host_frame_sink_client.h", "host_frame_sink_manager.cc", "host_frame_sink_manager.h", + "renderer_settings_creation.cc", + "renderer_settings_creation.h", "server_gpu_memory_buffer_manager.cc", "server_gpu_memory_buffer_manager.h", "viz_host_export.h", @@ -22,6 +24,8 @@ "//gpu/ipc/client", "//gpu/ipc/common", "//services/ui/gpu/interfaces", + "//ui/base", + "//ui/gfx", # TODO(kylechar): This is temporary and will be removed when all host to # service communication is over Mojo.
diff --git a/ui/compositor/compositor_util.cc b/components/viz/host/renderer_settings_creation.cc similarity index 61% rename from ui/compositor/compositor_util.cc rename to components/viz/host/renderer_settings_creation.cc index d0f5026..8f922a7c 100644 --- a/ui/compositor/compositor_util.cc +++ b/components/viz/host/renderer_settings_creation.cc
@@ -2,27 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/compositor/compositor_util.h" +#include "components/viz/host/renderer_settings_creation.h" #include "base/command_line.h" -#include "cc/base/switches.h" +#include "base/feature_list.h" +#include "build/build_config.h" #include "components/viz/common/display/renderer_settings.h" -#include "ui/compositor/compositor_switches.h" -#include "ui/display/display_switches.h" +#include "ui/base/ui_base_switches.h" #include "ui/gfx/color_space_switches.h" -namespace ui { +namespace viz { -viz::ResourceSettings CreateResourceSettings( - const viz::BufferToTextureTargetMap& image_targets) { - viz::ResourceSettings resource_settings; +ResourceSettings CreateResourceSettings( + const BufferToTextureTargetMap& image_targets) { + ResourceSettings resource_settings; resource_settings.buffer_to_texture_target_map = image_targets; return resource_settings; } -viz::RendererSettings CreateRendererSettings( - const viz::BufferToTextureTargetMap& image_targets) { - viz::RendererSettings renderer_settings; +RendererSettings CreateRendererSettings( + const BufferToTextureTargetMap& image_targets) { + RendererSettings renderer_settings; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); renderer_settings.partial_swap_enabled = !command_line->HasSwitch(switches::kUIDisablePartialSwap); @@ -33,21 +33,21 @@ #endif renderer_settings.gl_composited_overlay_candidate_quad_border = command_line->HasSwitch( - cc::switches::kGlCompositedOverlayCandidateQuadBorder); + switches::kGlCompositedOverlayCandidateQuadBorder); renderer_settings.show_overdraw_feedback = - command_line->HasSwitch(cc::switches::kShowOverdrawFeedback); + command_line->HasSwitch(switches::kShowOverdrawFeedback); renderer_settings.enable_color_correct_rendering = base::FeatureList::IsEnabled(features::kColorCorrectRendering); renderer_settings.resource_settings = CreateResourceSettings(image_targets); renderer_settings.show_overdraw_feedback = base::CommandLine::ForCurrentProcess()->HasSwitch( - cc::switches::kShowOverdrawFeedback); + switches::kShowOverdrawFeedback); renderer_settings.disallow_non_exact_resource_reuse = - command_line->HasSwitch(cc::switches::kDisallowNonExactResourceReuse); + command_line->HasSwitch(switches::kDisallowNonExactResourceReuse); renderer_settings.allow_antialiasing = - !command_line->HasSwitch(cc::switches::kDisableCompositedAntialiasing); + !command_line->HasSwitch(switches::kDisableCompositedAntialiasing); return renderer_settings; } -} // namespace ui +} // namespace viz
diff --git a/components/viz/host/renderer_settings_creation.h b/components/viz/host/renderer_settings_creation.h new file mode 100644 index 0000000..3c8459a --- /dev/null +++ b/components/viz/host/renderer_settings_creation.h
@@ -0,0 +1,30 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_HOST_RENDERER_SETTINGS_CREATION_H_ +#define COMPONENTS_VIZ_HOST_RENDERER_SETTINGS_CREATION_H_ + +#include <stdint.h> + +#include "components/viz/common/resources/buffer_to_texture_target_map.h" +#include "components/viz/host/viz_host_export.h" + +namespace viz { +class RendererSettings; +class ResourceSettings; +} // namespace viz + +namespace viz { + +// |image_targets| is a map from every supported pair of GPU memory buffer +// usage/format to its GL texture target. +VIZ_HOST_EXPORT ResourceSettings +CreateResourceSettings(const BufferToTextureTargetMap& image_targets); + +VIZ_HOST_EXPORT RendererSettings +CreateRendererSettings(const BufferToTextureTargetMap& image_targets); + +} // namespace viz + +#endif // COMPONENTS_VIZ_HOST_RENDERER_SETTINGS_CREATION_H_
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn index 5edb4bb..52bd20e 100644 --- a/components/viz/service/BUILD.gn +++ b/components/viz/service/BUILD.gn
@@ -47,6 +47,8 @@ "display_embedder/server_shared_bitmap_manager.h", "display_embedder/shared_bitmap_allocation_notifier_impl.cc", "display_embedder/shared_bitmap_allocation_notifier_impl.h", + "frame_sinks/compositor_frame_sink_impl.cc", + "frame_sinks/compositor_frame_sink_impl.h", "frame_sinks/compositor_frame_sink_support.cc", "frame_sinks/compositor_frame_sink_support.h", "frame_sinks/compositor_frame_sink_support_client.h", @@ -60,14 +62,12 @@ "frame_sinks/frame_sink_manager_client.h", "frame_sinks/frame_sink_manager_impl.cc", "frame_sinks/frame_sink_manager_impl.h", - "frame_sinks/gpu_compositor_frame_sink.cc", - "frame_sinks/gpu_compositor_frame_sink.h", - "frame_sinks/gpu_root_compositor_frame_sink.cc", - "frame_sinks/gpu_root_compositor_frame_sink.h", "frame_sinks/primary_begin_frame_source.cc", "frame_sinks/primary_begin_frame_source.h", "frame_sinks/referenced_surface_tracker.cc", "frame_sinks/referenced_surface_tracker.h", + "frame_sinks/root_compositor_frame_sink_impl.cc", + "frame_sinks/root_compositor_frame_sink_impl.h", "frame_sinks/surface_resource_holder.cc", "frame_sinks/surface_resource_holder.h", "frame_sinks/surface_resource_holder_client.h",
diff --git a/components/viz/service/display_embedder/gpu_display_provider.cc b/components/viz/service/display_embedder/gpu_display_provider.cc index 9f4ca42..e59a33f 100644 --- a/components/viz/service/display_embedder/gpu_display_provider.cc +++ b/components/viz/service/display_embedder/gpu_display_provider.cc
@@ -23,6 +23,7 @@ #include "gpu/command_buffer/service/image_factory.h" #include "gpu/ipc/service/gpu_channel_manager.h" #include "gpu/ipc/service/gpu_memory_buffer_factory.h" +#include "ui/base/ui_base_switches.h" #if defined(USE_OZONE) #include "components/viz/service/display_embedder/display_output_surface_ozone.h" @@ -93,7 +94,6 @@ synthetic_begin_frame_source.get(), task_runner_.get(), max_frames_pending); - // The ownership of the BeginFrameSource is transfered to the caller. *begin_frame_source = std::move(synthetic_begin_frame_source);
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc new file mode 100644 index 0000000..d5fbdd5 --- /dev/null +++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.cc
@@ -0,0 +1,85 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/service/frame_sinks/compositor_frame_sink_impl.h" + +#include <utility> + +#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" + +namespace viz { + +CompositorFrameSinkImpl::CompositorFrameSinkImpl( + FrameSinkManagerImpl* frame_sink_manager, + const FrameSinkId& frame_sink_id, + mojom::CompositorFrameSinkRequest request, + mojom::CompositorFrameSinkClientPtr client) + : support_( + CompositorFrameSinkSupport::Create(this, + frame_sink_manager, + frame_sink_id, + false /* is_root */, + true /* needs_sync_points */)), + client_(std::move(client)), + compositor_frame_sink_binding_(this, std::move(request)) { + compositor_frame_sink_binding_.set_connection_error_handler( + base::Bind(&CompositorFrameSinkImpl::OnClientConnectionLost, + base::Unretained(this))); +} + +CompositorFrameSinkImpl::~CompositorFrameSinkImpl() = default; + +void CompositorFrameSinkImpl::SetNeedsBeginFrame(bool needs_begin_frame) { + support_->SetNeedsBeginFrame(needs_begin_frame); +} + +void CompositorFrameSinkImpl::SubmitCompositorFrame( + const LocalSurfaceId& local_surface_id, + cc::CompositorFrame frame, + mojom::HitTestRegionListPtr hit_test_region_list) { + // TODO(gklassen): Route hit-test data to the appropriate HitTestAggregator. + if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) { + compositor_frame_sink_binding_.CloseWithReason( + 1, "Surface invariants violation"); + OnClientConnectionLost(); + } +} + +void CompositorFrameSinkImpl::DidNotProduceFrame( + const BeginFrameAck& begin_frame_ack) { + support_->DidNotProduceFrame(begin_frame_ack); +} + +void CompositorFrameSinkImpl::DidReceiveCompositorFrameAck( + const std::vector<ReturnedResource>& resources) { + if (client_) + client_->DidReceiveCompositorFrameAck(resources); +} + +void CompositorFrameSinkImpl::OnBeginFrame(const BeginFrameArgs& args) { + if (client_) + client_->OnBeginFrame(args); +} + +void CompositorFrameSinkImpl::OnBeginFramePausedChanged(bool paused) { + if (client_) + client_->OnBeginFramePausedChanged(paused); +} + +void CompositorFrameSinkImpl::ReclaimResources( + const std::vector<ReturnedResource>& resources) { + if (client_) + client_->ReclaimResources(resources); +} + +void CompositorFrameSinkImpl::WillDrawSurface( + const LocalSurfaceId& local_surface_id, + const gfx::Rect& damage_rect) {} + +void CompositorFrameSinkImpl::OnClientConnectionLost() { + support_->frame_sink_manager()->OnClientConnectionLost( + support_->frame_sink_id()); +} + +} // namespace viz
diff --git a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h b/components/viz/service/frame_sinks/compositor_frame_sink_impl.h similarity index 75% rename from components/viz/service/frame_sinks/gpu_compositor_frame_sink.h rename to components/viz/service/frame_sinks/compositor_frame_sink_impl.h index 7150e34c..49793396 100644 --- a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.h +++ b/components/viz/service/frame_sinks/compositor_frame_sink_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_ -#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_ +#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_IMPL_H_ +#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_IMPL_H_ #include <memory> #include <vector> @@ -20,16 +20,16 @@ namespace viz { // Server side representation of a WindowSurface. -class GpuCompositorFrameSink +class CompositorFrameSinkImpl : public NON_EXPORTED_BASE(CompositorFrameSinkSupportClient), public NON_EXPORTED_BASE(mojom::CompositorFrameSink) { public: - GpuCompositorFrameSink(FrameSinkManagerImpl* frame_sink_manager, - const FrameSinkId& frame_sink_id, - mojom::CompositorFrameSinkRequest request, - mojom::CompositorFrameSinkClientPtr client); + CompositorFrameSinkImpl(FrameSinkManagerImpl* frame_sink_manager, + const FrameSinkId& frame_sink_id, + mojom::CompositorFrameSinkRequest request, + mojom::CompositorFrameSinkClientPtr client); - ~GpuCompositorFrameSink() override; + ~CompositorFrameSinkImpl() override; // mojom::CompositorFrameSink: void SetNeedsBeginFrame(bool needs_begin_frame) override; @@ -57,9 +57,9 @@ mojom::CompositorFrameSinkClientPtr client_; mojo::Binding<mojom::CompositorFrameSink> compositor_frame_sink_binding_; - DISALLOW_COPY_AND_ASSIGN(GpuCompositorFrameSink); + DISALLOW_COPY_AND_ASSIGN(CompositorFrameSinkImpl); }; } // namespace viz -#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_COMPOSITOR_FRAME_SINK_H_ +#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_COMPOSITOR_FRAME_SINK_IMPL_H_
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc index 0e07c38..749d7913 100644 --- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc +++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -10,10 +10,10 @@ #include "base/logging.h" #include "components/viz/service/display/display.h" #include "components/viz/service/display_embedder/display_provider.h" +#include "components/viz/service/frame_sinks/compositor_frame_sink_impl.h" #include "components/viz/service/frame_sinks/frame_sink_manager_client.h" -#include "components/viz/service/frame_sinks/gpu_compositor_frame_sink.h" -#include "components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h" #include "components/viz/service/frame_sinks/primary_begin_frame_source.h" +#include "components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h" #if DCHECK_IS_ON() #include <sstream> @@ -98,7 +98,7 @@ frame_sink_id, surface_handle, renderer_settings, &begin_frame_source); compositor_frame_sinks_[frame_sink_id] = - base::MakeUnique<GpuRootCompositorFrameSink>( + base::MakeUnique<RootCompositorFrameSinkImpl>( this, frame_sink_id, std::move(display), std::move(begin_frame_source), std::move(request), std::move(client), std::move(display_private_request)); @@ -112,7 +112,7 @@ DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id)); compositor_frame_sinks_[frame_sink_id] = - base::MakeUnique<GpuCompositorFrameSink>( + base::MakeUnique<CompositorFrameSinkImpl>( this, frame_sink_id, std::move(request), std::move(client)); }
diff --git a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc b/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc deleted file mode 100644 index 3485356..0000000 --- a/components/viz/service/frame_sinks/gpu_compositor_frame_sink.cc +++ /dev/null
@@ -1,84 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/viz/service/frame_sinks/gpu_compositor_frame_sink.h" - -#include <utility> - -#include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" - -namespace viz { - -GpuCompositorFrameSink::GpuCompositorFrameSink( - FrameSinkManagerImpl* frame_sink_manager, - const FrameSinkId& frame_sink_id, - mojom::CompositorFrameSinkRequest request, - mojom::CompositorFrameSinkClientPtr client) - : support_(CompositorFrameSinkSupport::Create( - this, - frame_sink_manager, - frame_sink_id, - false /* is_root */, - true /* needs_sync_points */)), - client_(std::move(client)), - compositor_frame_sink_binding_(this, std::move(request)) { - compositor_frame_sink_binding_.set_connection_error_handler(base::Bind( - &GpuCompositorFrameSink::OnClientConnectionLost, base::Unretained(this))); -} - -GpuCompositorFrameSink::~GpuCompositorFrameSink() = default; - -void GpuCompositorFrameSink::SetNeedsBeginFrame(bool needs_begin_frame) { - support_->SetNeedsBeginFrame(needs_begin_frame); -} - -void GpuCompositorFrameSink::SubmitCompositorFrame( - const LocalSurfaceId& local_surface_id, - cc::CompositorFrame frame, - mojom::HitTestRegionListPtr hit_test_region_list) { - // TODO(gklassen): Route hit-test data to the appropriate HitTestAggregator. - if (!support_->SubmitCompositorFrame(local_surface_id, std::move(frame))) { - compositor_frame_sink_binding_.CloseWithReason( - 1, "Surface invariants violation"); - OnClientConnectionLost(); - } -} - -void GpuCompositorFrameSink::DidNotProduceFrame( - const BeginFrameAck& begin_frame_ack) { - support_->DidNotProduceFrame(begin_frame_ack); -} - -void GpuCompositorFrameSink::DidReceiveCompositorFrameAck( - const std::vector<ReturnedResource>& resources) { - if (client_) - client_->DidReceiveCompositorFrameAck(resources); -} - -void GpuCompositorFrameSink::OnBeginFrame(const BeginFrameArgs& args) { - if (client_) - client_->OnBeginFrame(args); -} - -void GpuCompositorFrameSink::OnBeginFramePausedChanged(bool paused) { - if (client_) - client_->OnBeginFramePausedChanged(paused); -} - -void GpuCompositorFrameSink::ReclaimResources( - const std::vector<ReturnedResource>& resources) { - if (client_) - client_->ReclaimResources(resources); -} - -void GpuCompositorFrameSink::WillDrawSurface( - const LocalSurfaceId& local_surface_id, - const gfx::Rect& damage_rect) {} - -void GpuCompositorFrameSink::OnClientConnectionLost() { - support_->frame_sink_manager()->OnClientConnectionLost( - support_->frame_sink_id()); -} - -} // namespace viz
diff --git a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc similarity index 74% rename from components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc rename to components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc index 18759fc5..7065fba5 100644 --- a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.cc +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h" +#include "components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h" #include <utility> @@ -13,7 +13,7 @@ namespace viz { -GpuRootCompositorFrameSink::GpuRootCompositorFrameSink( +RootCompositorFrameSinkImpl::RootCompositorFrameSinkImpl( FrameSinkManagerImpl* frame_sink_manager, const FrameSinkId& frame_sink_id, std::unique_ptr<Display> display, @@ -35,50 +35,50 @@ hit_test_aggregator_(this) { DCHECK(display_begin_frame_source_); compositor_frame_sink_binding_.set_connection_error_handler( - base::Bind(&GpuRootCompositorFrameSink::OnClientConnectionLost, + base::Bind(&RootCompositorFrameSinkImpl::OnClientConnectionLost, base::Unretained(this))); frame_sink_manager->RegisterBeginFrameSource( display_begin_frame_source_.get(), frame_sink_id); display_->Initialize(this, frame_sink_manager->surface_manager()); } -GpuRootCompositorFrameSink::~GpuRootCompositorFrameSink() { +RootCompositorFrameSinkImpl::~RootCompositorFrameSinkImpl() { support_->frame_sink_manager()->UnregisterBeginFrameSource( display_begin_frame_source_.get()); } -void GpuRootCompositorFrameSink::SetDisplayVisible(bool visible) { +void RootCompositorFrameSinkImpl::SetDisplayVisible(bool visible) { DCHECK(display_); display_->SetVisible(visible); } -void GpuRootCompositorFrameSink::ResizeDisplay(const gfx::Size& size) { +void RootCompositorFrameSinkImpl::ResizeDisplay(const gfx::Size& size) { DCHECK(display_); display_->Resize(size); } -void GpuRootCompositorFrameSink::SetDisplayColorSpace( +void RootCompositorFrameSinkImpl::SetDisplayColorSpace( const gfx::ColorSpace& color_space) { DCHECK(display_); display_->SetColorSpace(color_space, color_space); } -void GpuRootCompositorFrameSink::SetOutputIsSecure(bool secure) { +void RootCompositorFrameSinkImpl::SetOutputIsSecure(bool secure) { DCHECK(display_); display_->SetOutputIsSecure(secure); } -void GpuRootCompositorFrameSink::SetLocalSurfaceId( +void RootCompositorFrameSinkImpl::SetLocalSurfaceId( const LocalSurfaceId& local_surface_id, float scale_factor) { display_->SetLocalSurfaceId(local_surface_id, scale_factor); } -void GpuRootCompositorFrameSink::SetNeedsBeginFrame(bool needs_begin_frame) { +void RootCompositorFrameSinkImpl::SetNeedsBeginFrame(bool needs_begin_frame) { support_->SetNeedsBeginFrame(needs_begin_frame); } -void GpuRootCompositorFrameSink::SubmitCompositorFrame( +void RootCompositorFrameSinkImpl::SubmitCompositorFrame( const LocalSurfaceId& local_surface_id, cc::CompositorFrame frame, mojom::HitTestRegionListPtr hit_test_region_list) { @@ -91,12 +91,12 @@ } } -void GpuRootCompositorFrameSink::DidNotProduceFrame( +void RootCompositorFrameSinkImpl::DidNotProduceFrame( const BeginFrameAck& begin_frame_ack) { support_->DidNotProduceFrame(begin_frame_ack); } -void GpuRootCompositorFrameSink::OnAggregatedHitTestRegionListUpdated( +void RootCompositorFrameSinkImpl::OnAggregatedHitTestRegionListUpdated( mojo::ScopedSharedBufferHandle active_handle, uint32_t active_handle_size, mojo::ScopedSharedBufferHandle idle_handle, @@ -106,53 +106,53 @@ std::move(idle_handle), idle_handle_size); } -void GpuRootCompositorFrameSink::SwitchActiveAggregatedHitTestRegionList( +void RootCompositorFrameSinkImpl::SwitchActiveAggregatedHitTestRegionList( uint8_t active_handle_index) { support_->frame_sink_manager()->SwitchActiveAggregatedHitTestRegionList( support_->frame_sink_id(), active_handle_index); } -void GpuRootCompositorFrameSink::DisplayOutputSurfaceLost() { +void RootCompositorFrameSinkImpl::DisplayOutputSurfaceLost() { // TODO(staraz): Implement this. Client should hear about context/output // surface lost. } -void GpuRootCompositorFrameSink::DisplayWillDrawAndSwap( +void RootCompositorFrameSinkImpl::DisplayWillDrawAndSwap( bool will_draw_and_swap, const cc::RenderPassList& render_pass) { hit_test_aggregator_.PostTaskAggregate(display_->CurrentSurfaceId()); } -void GpuRootCompositorFrameSink::DisplayDidDrawAndSwap() {} +void RootCompositorFrameSinkImpl::DisplayDidDrawAndSwap() {} -void GpuRootCompositorFrameSink::DidReceiveCompositorFrameAck( +void RootCompositorFrameSinkImpl::DidReceiveCompositorFrameAck( const std::vector<ReturnedResource>& resources) { if (client_) client_->DidReceiveCompositorFrameAck(resources); } -void GpuRootCompositorFrameSink::OnBeginFrame(const BeginFrameArgs& args) { +void RootCompositorFrameSinkImpl::OnBeginFrame(const BeginFrameArgs& args) { hit_test_aggregator_.Swap(); if (client_) client_->OnBeginFrame(args); } -void GpuRootCompositorFrameSink::OnBeginFramePausedChanged(bool paused) { +void RootCompositorFrameSinkImpl::OnBeginFramePausedChanged(bool paused) { if (client_) client_->OnBeginFramePausedChanged(paused); } -void GpuRootCompositorFrameSink::ReclaimResources( +void RootCompositorFrameSinkImpl::ReclaimResources( const std::vector<ReturnedResource>& resources) { if (client_) client_->ReclaimResources(resources); } -void GpuRootCompositorFrameSink::WillDrawSurface( +void RootCompositorFrameSinkImpl::WillDrawSurface( const LocalSurfaceId& local_surface_id, const gfx::Rect& damage_rect) {} -void GpuRootCompositorFrameSink::OnClientConnectionLost() { +void RootCompositorFrameSinkImpl::OnClientConnectionLost() { support_->frame_sink_manager()->OnClientConnectionLost( support_->frame_sink_id()); }
diff --git a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h similarity index 88% rename from components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h rename to components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h index 375d119..38eaeee 100644 --- a/components/viz/service/frame_sinks/gpu_root_compositor_frame_sink.h +++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_ -#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_ +#ifndef COMPONENTS_VIZ_SERVICE_FRAME_SINKS_ROOT_COMPOSITOR_FRAME_SINK_IMPL_H_ +#define COMPONENTS_VIZ_SERVICE_FRAME_SINKS_ROOT_COMPOSITOR_FRAME_SINK_IMPL_H_ #include <memory> @@ -25,14 +25,14 @@ class Display; class FrameSinkManagerImpl; -class GpuRootCompositorFrameSink +class RootCompositorFrameSinkImpl : public NON_EXPORTED_BASE(CompositorFrameSinkSupportClient), public NON_EXPORTED_BASE(mojom::CompositorFrameSink), public NON_EXPORTED_BASE(mojom::DisplayPrivate), public NON_EXPORTED_BASE(DisplayClient), public HitTestAggregatorDelegate { public: - GpuRootCompositorFrameSink( + RootCompositorFrameSinkImpl( FrameSinkManagerImpl* frame_sink_manager, const FrameSinkId& frame_sink_id, std::unique_ptr<Display> display, @@ -41,7 +41,7 @@ mojom::CompositorFrameSinkClientPtr client, mojom::DisplayPrivateAssociatedRequest display_private_request); - ~GpuRootCompositorFrameSink() override; + ~RootCompositorFrameSinkImpl() override; // mojom::DisplayPrivate: void SetDisplayVisible(bool visible) override; @@ -89,7 +89,7 @@ std::unique_ptr<CompositorFrameSinkSupport> support_; - // GpuRootCompositorFrameSink holds a Display and its BeginFrameSource if + // RootCompositorFrameSinkImpl holds a Display and its BeginFrameSource if // it was created with a non-null gpu::SurfaceHandle. std::unique_ptr<BeginFrameSource> display_begin_frame_source_; std::unique_ptr<Display> display_; @@ -101,9 +101,9 @@ HitTestAggregator hit_test_aggregator_; - DISALLOW_COPY_AND_ASSIGN(GpuRootCompositorFrameSink); + DISALLOW_COPY_AND_ASSIGN(RootCompositorFrameSinkImpl); }; } // namespace viz -#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_GPU_ROOT_COMPOSITOR_FRAME_SINK_H_ +#endif // COMPONENTS_VIZ_SERVICE_FRAME_SINKS_ROOT_COMPOSITOR_FRAME_SINK_IMPL_H_
diff --git a/content/browser/appcache/appcache_backend_impl.cc b/content/browser/appcache/appcache_backend_impl.cc index c079515..6c60508 100644 --- a/content/browser/appcache/appcache_backend_impl.cc +++ b/content/browser/appcache/appcache_backend_impl.cc
@@ -99,13 +99,14 @@ return host->MarkAsForeignEntry(document_url, cache_document_was_loaded_from); } -bool AppCacheBackendImpl::GetStatusWithCallback( - int host_id, const GetStatusCallback& callback, void* callback_param) { +bool AppCacheBackendImpl::GetStatusWithCallback(int host_id, + GetStatusCallback callback, + void* callback_param) { AppCacheHost* host = GetHost(host_id); if (!host) return false; - host->GetStatusWithCallback(callback, callback_param); + host->GetStatusWithCallback(std::move(callback), callback_param); return true; }
diff --git a/content/browser/appcache/appcache_backend_impl.h b/content/browser/appcache/appcache_backend_impl.h index 83e64632..6c6b90b 100644 --- a/content/browser/appcache/appcache_backend_impl.h +++ b/content/browser/appcache/appcache_backend_impl.h
@@ -44,7 +44,8 @@ bool MarkAsForeignEntry(int host_id, const GURL& document_url, int64_t cache_document_was_loaded_from); - bool GetStatusWithCallback(int host_id, const GetStatusCallback& callback, + bool GetStatusWithCallback(int host_id, + GetStatusCallback callback, void* callback_param); bool StartUpdateWithCallback(int host_id, const StartUpdateCallback& callback, void* callback_param);
diff --git a/content/browser/appcache/appcache_dispatcher_host.cc b/content/browser/appcache/appcache_dispatcher_host.cc index 37fee079..2d18a23 100644 --- a/content/browser/appcache/appcache_dispatcher_host.cc +++ b/content/browser/appcache/appcache_dispatcher_host.cc
@@ -31,8 +31,6 @@ backend_impl_.Initialize(appcache_service_.get(), &frontend_proxy_, process_id_); - get_status_callback_ = base::Bind(&AppCacheDispatcherHost::GetStatusCallback, - weak_factory_.GetWeakPtr()); start_update_callback_ = base::Bind( &AppCacheDispatcherHost::StartUpdateCallback, weak_factory_.GetWeakPtr()); swap_cache_callback_ = base::Bind(&AppCacheDispatcherHost::SwapCacheCallback, @@ -169,8 +167,11 @@ pending_reply_msg_.reset(reply_msg); if (appcache_service_.get()) { - if (!backend_impl_.GetStatusWithCallback(host_id, get_status_callback_, - reply_msg)) { + if (!backend_impl_.GetStatusWithCallback( + host_id, + base::BindOnce(&AppCacheDispatcherHost::GetStatusCallback, + weak_factory_.GetWeakPtr()), + reply_msg)) { bad_message::ReceivedBadMessage(this, bad_message::ACDH_GET_STATUS); } return;
diff --git a/content/browser/appcache/appcache_dispatcher_host.h b/content/browser/appcache/appcache_dispatcher_host.h index 0b4b16e..be503446 100644 --- a/content/browser/appcache/appcache_dispatcher_host.h +++ b/content/browser/appcache/appcache_dispatcher_host.h
@@ -66,7 +66,6 @@ AppCacheFrontendProxy frontend_proxy_; AppCacheBackendImpl backend_impl_; - content::GetStatusCallback get_status_callback_; content::StartUpdateCallback start_update_callback_; content::SwapCacheCallback swap_cache_callback_; std::unique_ptr<IPC::Message> pending_reply_msg_;
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc index ecfa39c..609121f 100644 --- a/content/browser/appcache/appcache_host.cc +++ b/content/browser/appcache/appcache_host.cc
@@ -210,13 +210,13 @@ return true; } -void AppCacheHost::GetStatusWithCallback(const GetStatusCallback& callback, +void AppCacheHost::GetStatusWithCallback(GetStatusCallback callback, void* callback_param) { DCHECK(pending_start_update_callback_.is_null() && pending_swap_cache_callback_.is_null() && pending_get_status_callback_.is_null()); - pending_get_status_callback_ = callback; + pending_get_status_callback_ = std::move(callback); pending_callback_param_ = callback_param; if (is_selection_pending()) return; @@ -227,8 +227,8 @@ void AppCacheHost::DoPendingGetStatus() { DCHECK_EQ(false, pending_get_status_callback_.is_null()); - pending_get_status_callback_.Run(GetStatus(), pending_callback_param_); - pending_get_status_callback_.Reset(); + std::move(pending_get_status_callback_) + .Run(GetStatus(), pending_callback_param_); pending_callback_param_ = NULL; } @@ -259,8 +259,8 @@ } } - pending_start_update_callback_.Run(success, pending_callback_param_); - pending_start_update_callback_.Reset(); + std::move(pending_start_update_callback_) + .Run(success, pending_callback_param_); pending_callback_param_ = NULL; } @@ -295,8 +295,7 @@ } } - pending_swap_cache_callback_.Run(success, pending_callback_param_); - pending_swap_cache_callback_.Reset(); + std::move(pending_swap_cache_callback_).Run(success, pending_callback_param_); pending_callback_param_ = NULL; }
diff --git a/content/browser/appcache/appcache_host.h b/content/browser/appcache/appcache_host.h index 2cbf435..c237e5f 100644 --- a/content/browser/appcache/appcache_host.h +++ b/content/browser/appcache/appcache_host.h
@@ -52,7 +52,7 @@ class AppCacheTest; class AppCacheUpdateJobTest; -typedef base::Callback<void(AppCacheStatus, void*)> GetStatusCallback; +typedef base::OnceCallback<void(AppCacheStatus, void*)> GetStatusCallback; typedef base::Callback<void(bool, void*)> StartUpdateCallback; typedef base::Callback<void(bool, void*)> SwapCacheCallback; @@ -92,8 +92,7 @@ bool SelectCacheForSharedWorker(int64_t appcache_id); bool MarkAsForeignEntry(const GURL& document_url, int64_t cache_document_was_loaded_from); - void GetStatusWithCallback(const GetStatusCallback& callback, - void* callback_param); + void GetStatusWithCallback(GetStatusCallback callback, void* callback_param); void StartUpdateWithCallback(const StartUpdateCallback& callback, void* callback_param); void SwapCacheWithCallback(const SwapCacheCallback& callback,
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc index 16c3626..eac9155 100644 --- a/content/browser/appcache/appcache_host_unittest.cc +++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -25,9 +25,8 @@ class AppCacheHostTest : public testing::Test { public: AppCacheHostTest() { - get_status_callback_ = - base::Bind(&AppCacheHostTest::GetStatusCallback, - base::Unretained(this)); + get_status_callback_ = base::BindRepeating( + &AppCacheHostTest::GetStatusCallback, base::Unretained(this)); start_update_callback_ = base::Bind(&AppCacheHostTest::StartUpdateCallback, base::Unretained(this)); @@ -177,7 +176,8 @@ // See that the callbacks are delivered immediately // and respond as if there is no cache selected. last_status_result_ = APPCACHE_STATUS_OBSOLETE; - host.GetStatusWithCallback(get_status_callback_, reinterpret_cast<void*>(1)); + host.GetStatusWithCallback(std::move(get_status_callback_), + reinterpret_cast<void*>(1)); EXPECT_EQ(APPCACHE_STATUS_UNCACHED, last_status_result_); EXPECT_EQ(reinterpret_cast<void*>(1), last_callback_param_); @@ -301,7 +301,8 @@ // The callback should not occur until we finish cache selection. last_status_result_ = APPCACHE_STATUS_OBSOLETE; last_callback_param_ = reinterpret_cast<void*>(-1); - host.GetStatusWithCallback(get_status_callback_, reinterpret_cast<void*>(1)); + host.GetStatusWithCallback(std::move(get_status_callback_), + reinterpret_cast<void*>(1)); EXPECT_EQ(APPCACHE_STATUS_OBSOLETE, last_status_result_); EXPECT_EQ(reinterpret_cast<void*>(-1), last_callback_param_); @@ -332,7 +333,8 @@ // The callback should not occur until we finish cache selection. last_status_result_ = APPCACHE_STATUS_OBSOLETE; last_callback_param_ = reinterpret_cast<void*>(-1); - host.GetStatusWithCallback(get_status_callback_, reinterpret_cast<void*>(1)); + host.GetStatusWithCallback(std::move(get_status_callback_), + reinterpret_cast<void*>(1)); EXPECT_EQ(APPCACHE_STATUS_OBSOLETE, last_status_result_); EXPECT_EQ(reinterpret_cast<void*>(-1), last_callback_param_);
diff --git a/content/browser/compositor/gpu_process_transport_factory.cc b/content/browser/compositor/gpu_process_transport_factory.cc index 1a1d723..dee8f01 100644 --- a/content/browser/compositor/gpu_process_transport_factory.cc +++ b/content/browser/compositor/gpu_process_transport_factory.cc
@@ -29,6 +29,7 @@ #include "components/viz/common/frame_sinks/delay_based_time_source.h" #include "components/viz/common/gl_helper.h" #include "components/viz/host/host_frame_sink_manager.h" +#include "components/viz/host/renderer_settings_creation.h" #include "components/viz/service/display/display.h" #include "components/viz/service/display/display_scheduler.h" #include "components/viz/service/display_embedder/compositor_overlay_candidate_validator.h" @@ -60,7 +61,6 @@ #include "ui/compositor/compositor.h" #include "ui/compositor/compositor_constants.h" #include "ui/compositor/compositor_switches.h" -#include "ui/compositor/compositor_util.h" #include "ui/compositor/layer.h" #include "ui/display/display_switches.h" #include "ui/display/types/display_snapshot.h" @@ -235,7 +235,7 @@ scoped_refptr<base::SingleThreadTaskRunner> resize_task_runner) : frame_sink_id_allocator_(kDefaultClientId), renderer_settings_( - ui::CreateRendererSettings(CreateBufferToTextureTargetMap())), + viz::CreateRendererSettings(CreateBufferToTextureTargetMap())), resize_task_runner_(std::move(resize_task_runner)), task_graph_runner_(new cc::SingleThreadTaskGraphRunner), callback_factory_(this) {
diff --git a/content/browser/frame_host/navigator_impl_unittest.cc b/content/browser/frame_host/navigator_impl_unittest.cc index 99fd473..a9574ec 100644 --- a/content/browser/frame_host/navigator_impl_unittest.cc +++ b/content/browser/frame_host/navigator_impl_unittest.cc
@@ -27,6 +27,7 @@ #include "content/public/common/url_utils.h" #include "content/public/test/browser_side_navigation_test_utils.h" #include "content/public/test/mock_render_process_host.h" +#include "content/public/test/navigation_simulator.h" #include "content/public/test/test_utils.h" #include "content/test/test_navigation_url_loader.h" #include "content/test/test_render_frame_host.h" @@ -1009,9 +1010,10 @@ // Do a renderer-initiated navigation to a data url. The request should be // sent to the IO thread. - TestRenderFrameHost* main_rfh = main_test_rfh(); - main_rfh->SendRendererInitiatedNavigationRequest(kUrl2, true); - EXPECT_TRUE(main_rfh->is_loading()); + auto navigation_to_data_url = + NavigationSimulator::CreateRendererInitiated(kUrl2, main_test_rfh()); + navigation_to_data_url->Start(); + EXPECT_TRUE(main_test_rfh()->is_loading()); EXPECT_TRUE(node->navigation_request()); EXPECT_FALSE(GetSpeculativeRenderFrameHost(node)); }
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc index 1434b848..19d0a4e3 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -46,6 +46,7 @@ #include "content/public/common/url_utils.h" #include "content/public/test/browser_side_navigation_test_utils.h" #include "content/public/test/mock_render_process_host.h" +#include "content/public/test/navigation_simulator.h" #include "content/public/test/test_notification_tracker.h" #include "content/public/test/test_utils.h" #include "content/test/test_content_browser_client.h" @@ -3124,7 +3125,9 @@ // The initial RFH receives a BeginNavigation IPC. The navigation should not // start. - initial_rfh->SendRendererInitiatedNavigationRequest(kUrl3, true); + auto navigation = + NavigationSimulator::CreateRendererInitiated(kUrl3, initial_rfh); + navigation->Start(); EXPECT_FALSE(main_test_rfh()->frame_tree_node()->navigation_request()); }
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc index 9a8a794..b1f39e7 100644 --- a/content/browser/frame_host/render_widget_host_view_child_frame.cc +++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -816,10 +816,22 @@ } } - // TODO(mcnee): Allow the root RWHV to consume the child's - // GestureScrollUpdates. This is needed to prevent the child from consuming - // them after the root has started an overscroll. - // See crbug.com/713368 + // Allow the root RWHV a chance to consume the child's GestureScrollUpdates + // in case the root needs to prevent the child from scrolling. For example, + // if the root has started an overscroll gesture, it needs to process the + // scroll events that would normally be processed by the child. + // TODO(mcnee): Once BrowserPlugin is removed, investigate routing these + // GestureScrollUpdates directly to the root RWHV during an overscroll + // gesture. The way resending of scroll events from a plugin works would cause + // issues with this approach in terms of valid input streams. + // See crbug.com/751782 + if (frame_connector_ && + input_event.GetType() == blink::WebInputEvent::kGestureScrollUpdate) { + const blink::WebGestureEvent& gesture_event = + static_cast<const blink::WebGestureEvent&>(input_event); + return frame_connector_->GetRootRenderWidgetHostView() + ->FilterChildGestureEvent(gesture_event); + } return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; }
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc index c95d63b4..7b3faf6 100644 --- a/content/browser/gpu/gpu_process_host.cc +++ b/content/browser/gpu/gpu_process_host.cc
@@ -65,6 +65,7 @@ #include "services/service_manager/public/cpp/binder_registry.h" #include "services/service_manager/public/cpp/interface_provider.h" #include "services/service_manager/runner/common/client_util.h" +#include "ui/base/ui_base_switches.h" #include "ui/display/display_switches.h" #include "ui/gfx/color_space_switches.h" #include "ui/gfx/switches.h" @@ -98,10 +99,6 @@ #include "gpu/ipc/common/gpu_surface_tracker.h" #endif -#if defined(OS_MACOSX) -#include "ui/base/ui_base_switches.h" -#endif - namespace content { bool GpuProcessHost::gpu_enabled_ = true;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index a1dbca3b..1adfb73 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -2594,7 +2594,6 @@ // also be added to chrome/browser/chromeos/login/chrome_restart_request.cc. cc::switches::kDisableCompositedAntialiasing, cc::switches::kDisableThreadedAnimation, - cc::switches::kDisallowNonExactResourceReuse, cc::switches::kEnableGpuBenchmarking, cc::switches::kEnableLayerLists, cc::switches::kEnableTileCompression, @@ -2625,6 +2624,7 @@ #endif switches::kEnableLowEndDeviceMode, switches::kDisableLowEndDeviceMode, + switches::kDisallowNonExactResourceReuse, #if defined(OS_ANDROID) switches::kDisableMediaSessionAPI, switches::kRendererWaitForJavaDebugger,
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc index 48918fe..42ae340 100644 --- a/content/browser/renderer_host/render_widget_host_impl.cc +++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -85,6 +85,7 @@ #include "storage/browser/fileapi/isolated_context.h" #include "third_party/WebKit/public/web/WebCompositionUnderline.h" #include "ui/base/clipboard/clipboard.h" +#include "ui/base/ui_base_switches.h" #include "ui/display/display_switches.h" #include "ui/events/blink/web_input_event_traits.h" #include "ui/events/event.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc index 9c99a34..089869f5 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.cc +++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -1798,6 +1798,14 @@ return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; } +InputEventAckState RenderWidgetHostViewAndroid::FilterChildGestureEvent( + const blink::WebGestureEvent& gesture_event) { + if (overscroll_controller_ && + overscroll_controller_->WillHandleGestureEvent(gesture_event)) + return INPUT_EVENT_ACK_STATE_CONSUMED; + return INPUT_EVENT_ACK_STATE_NOT_CONSUMED; +} + BrowserAccessibilityManager* RenderWidgetHostViewAndroid::CreateBrowserAccessibilityManager( BrowserAccessibilityDelegate* delegate, bool for_root_frame) { @@ -2417,4 +2425,11 @@ overscroll_refresh_handler, compositor, view_.GetDipScale()); } +void RenderWidgetHostViewAndroid::SetOverscrollControllerForTesting( + ui::OverscrollRefreshHandler* overscroll_refresh_handler) { + overscroll_controller_ = base::MakeUnique<OverscrollControllerAndroid>( + overscroll_refresh_handler, view_.GetWindowAndroid()->GetCompositor(), + view_.GetDipScale()); +} + } // namespace content
diff --git a/content/browser/renderer_host/render_widget_host_view_android.h b/content/browser/renderer_host/render_widget_host_view_android.h index 57e85ed..cd82c4e 100644 --- a/content/browser/renderer_host/render_widget_host_view_android.h +++ b/content/browser/renderer_host/render_widget_host_view_android.h
@@ -44,6 +44,7 @@ namespace ui { class MotionEventAndroid; +class OverscrollRefreshHandler; struct DidOverscrollParams; } @@ -143,6 +144,8 @@ InputEventAckState ack_result) override; InputEventAckState FilterInputEvent( const blink::WebInputEvent& input_event) override; + InputEventAckState FilterChildGestureEvent( + const blink::WebGestureEvent& gesture_event) override; void GestureEventAck(const blink::WebGestureEvent& event, InputEventAckState ack_result) override; BrowserAccessibilityManager* CreateBrowserAccessibilityManager( @@ -320,6 +323,9 @@ void SetSelectionControllerClientForTesting( std::unique_ptr<ui::TouchSelectionControllerClient> client); + void SetOverscrollControllerForTesting( + ui::OverscrollRefreshHandler* overscroll_refresh_handler); + void GotFocus(); void LostFocus();
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index d6480b6..e40ac83 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -76,6 +76,7 @@ #include "content/public/test/test_utils.h" #include "content/shell/browser/shell.h" #include "content/test/content_browser_test_utils_internal.h" +#include "content/test/mock_overscroll_observer.h" #include "ipc/ipc.mojom.h" #include "ipc/ipc_security_test_util.h" #include "mojo/public/cpp/bindings/strong_binding.h" @@ -101,7 +102,10 @@ #include "ui/native_theme/native_theme_features.h" #if defined(USE_AURA) +#include "content/browser/renderer_host/overscroll_controller.h" #include "content/browser/renderer_host/render_widget_host_view_aura.h" +#include "content/public/browser/overscroll_configuration.h" +#include "content/test/mock_overscroll_controller_delegate_aura.h" #endif #if defined(OS_MACOSX) @@ -116,6 +120,7 @@ #include "content/browser/android/ime_adapter_android.h" #include "content/browser/renderer_host/input/touch_selection_controller_client_manager_android.h" #include "content/browser/renderer_host/render_widget_host_view_android.h" +#include "content/test/mock_overscroll_refresh_handler_android.h" #include "ui/gfx/geometry/point_f.h" #endif @@ -1412,6 +1417,209 @@ DCHECK_EQ(filter->last_rect().y(), 0); } +#if defined(USE_AURA) || defined(OS_ANDROID) + +// When unconsumed scrolls in a child bubble to the root and start an +// overscroll gesture, the subsequent gesture scroll update events should be +// consumed by the root. The child should not be able to scroll during the +// overscroll gesture. +IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, + RootConsumesScrollDuringOverscrollGesture) { + GURL main_url(embedded_test_server()->GetURL( + "a.com", "/cross_site_iframe_factory.html?a(b)")); + EXPECT_TRUE(NavigateToURL(shell(), main_url)); + + FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetFrameTree() + ->root(); + RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>( + root->current_frame_host()->GetRenderWidgetHost()->GetView()); + ASSERT_EQ(1U, root->child_count()); + + FrameTreeNode* child_node = root->child_at(0); + +#if defined(USE_AURA) + // The child must be horizontally scrollable. + GURL child_url(embedded_test_server()->GetURL("b.com", "/wide_page.html")); +#elif defined(OS_ANDROID) + // The child must be vertically scrollable. + GURL child_url(embedded_test_server()->GetURL("b.com", "/tall_page.html")); +#endif + NavigateFrameToURL(child_node, child_url); + + EXPECT_EQ( + " Site A ------------ proxies for B\n" + " +--Site B ------- proxies for A\n" + "Where A = http://a.com/\n" + " B = http://b.com/", + DepictFrameTree(root)); + + RenderWidgetHostViewChildFrame* rwhv_child = + static_cast<RenderWidgetHostViewChildFrame*>( + child_node->current_frame_host()->GetRenderWidgetHost()->GetView()); + + WaitForChildFrameSurfaceReady(child_node->current_frame_host()); + + ASSERT_EQ(gfx::Vector2dF(), rwhv_root->GetLastScrollOffset()); + ASSERT_EQ(gfx::Vector2dF(), rwhv_child->GetLastScrollOffset()); + + RenderWidgetHostInputEventRouter* router = + static_cast<WebContentsImpl*>(shell()->web_contents()) + ->GetInputEventRouter(); + + { + // Set up the RenderWidgetHostInputEventRouter to send the gesture stream + // to the child. + const gfx::Rect root_bounds = rwhv_root->GetViewBounds(); + const gfx::Rect child_bounds = rwhv_child->GetViewBounds(); + const float page_scale_factor = GetPageScaleFactor(shell()); + const gfx::Point point_in_child( + gfx::ToCeiledInt((child_bounds.x() - root_bounds.x() + 10) * + page_scale_factor), + gfx::ToCeiledInt((child_bounds.y() - root_bounds.y() + 10) * + page_scale_factor)); + gfx::Point dont_care; + ASSERT_EQ(rwhv_child->GetRenderWidgetHost(), + router->GetRenderWidgetHostAtPoint(rwhv_root, point_in_child, + &dont_care)); + + blink::WebTouchEvent touch_event( + blink::WebInputEvent::kTouchStart, blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + touch_event.touches_length = 1; + touch_event.touches[0].state = blink::WebTouchPoint::kStatePressed; + touch_event.touches[0].SetPositionInWidget(point_in_child.x(), + point_in_child.y()); + touch_event.unique_touch_event_id = 1; + router->RouteTouchEvent(rwhv_root, &touch_event, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + + blink::WebGestureEvent gesture_event( + blink::WebInputEvent::kGestureTapDown, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_event.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_event.unique_touch_event_id = touch_event.unique_touch_event_id; + router->RouteGestureEvent(rwhv_root, &gesture_event, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + } + +#if defined(USE_AURA) + RenderWidgetHostViewAura* rwhva = + static_cast<RenderWidgetHostViewAura*>(rwhv_root); + std::unique_ptr<MockOverscrollControllerDelegateAura> + mock_overscroll_delegate = + base::MakeUnique<MockOverscrollControllerDelegateAura>(rwhva); + rwhva->overscroll_controller()->set_delegate(mock_overscroll_delegate.get()); + MockOverscrollObserver* mock_overscroll_observer = + mock_overscroll_delegate.get(); +#elif defined(OS_ANDROID) + RenderWidgetHostViewAndroid* rwhv_android = + static_cast<RenderWidgetHostViewAndroid*>(rwhv_root); + std::unique_ptr<MockOverscrollRefreshHandlerAndroid> mock_overscroll_handler = + base::MakeUnique<MockOverscrollRefreshHandlerAndroid>(); + rwhv_android->SetOverscrollControllerForTesting( + mock_overscroll_handler.get()); + MockOverscrollObserver* mock_overscroll_observer = + mock_overscroll_handler.get(); +#endif // defined(USE_AURA) + + std::unique_ptr<InputEventAckWaiter> gesture_begin_observer_child = + base::MakeUnique<InputEventAckWaiter>( + blink::WebInputEvent::kGestureScrollBegin); + child_node->current_frame_host() + ->GetRenderWidgetHost() + ->AddInputEventObserver(gesture_begin_observer_child.get()); + std::unique_ptr<InputEventAckWaiter> gesture_end_observer_child = + base::MakeUnique<InputEventAckWaiter>( + blink::WebInputEvent::kGestureScrollEnd); + child_node->current_frame_host() + ->GetRenderWidgetHost() + ->AddInputEventObserver(gesture_end_observer_child.get()); + + // First we need our scroll to initiate an overscroll gesture in the root + // via unconsumed scrolls in the child. + blink::WebGestureEvent gesture_scroll_begin( + blink::WebGestureEvent::kGestureScrollBegin, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_scroll_begin.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_scroll_begin.unique_touch_event_id = 1; + gesture_scroll_begin.data.scroll_begin.delta_hint_units = + blink::WebGestureEvent::ScrollUnits::kPrecisePixels; + gesture_scroll_begin.data.scroll_begin.delta_x_hint = 0.f; + gesture_scroll_begin.data.scroll_begin.delta_y_hint = 0.f; + router->RouteGestureEvent(rwhv_root, &gesture_scroll_begin, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + + // Make sure the child is indeed receiving the gesture stream. + gesture_begin_observer_child->Wait(); + + blink::WebGestureEvent gesture_scroll_update( + blink::WebGestureEvent::kGestureScrollUpdate, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_scroll_update.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_scroll_update.unique_touch_event_id = 1; + gesture_scroll_update.data.scroll_update.delta_units = + blink::WebGestureEvent::ScrollUnits::kPrecisePixels; + gesture_scroll_update.data.scroll_update.delta_x = 0.f; + gesture_scroll_update.data.scroll_update.delta_y = 0.f; +#if defined(USE_AURA) + const float threshold = + GetOverscrollConfig(OVERSCROLL_CONFIG_HORIZ_THRESHOLD_START_TOUCHSCREEN); + // For aura, we scroll horizontally to activate an overscroll navigation. + float* delta = &gesture_scroll_update.data.scroll_update.delta_x; +#elif defined(OS_ANDROID) + const float threshold = 0.f; + // For android, we scroll vertically to activate pull-to-refresh. + float* delta = &gesture_scroll_update.data.scroll_update.delta_y; +#endif + *delta = threshold + 1; + mock_overscroll_observer->Reset(); + // This will bring us into an overscroll gesture. + router->RouteGestureEvent(rwhv_root, &gesture_scroll_update, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + // Note that in addition to verifying that we get the overscroll update, it + // is necessary to wait before sending the next event to prevent our multiple + // GestureScrollUpdates from being coalesced. + mock_overscroll_observer->WaitForUpdate(); + + // This scroll is in the same direction and so it will contribute to the + // overscroll. + *delta = 10.0f; + mock_overscroll_observer->Reset(); + router->RouteGestureEvent(rwhv_root, &gesture_scroll_update, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + mock_overscroll_observer->WaitForUpdate(); + + // Now we reverse direction. The child could scroll in this direction, but + // since we're in an overscroll gesture, the root should consume it. + *delta = -5.0f; + mock_overscroll_observer->Reset(); + router->RouteGestureEvent(rwhv_root, &gesture_scroll_update, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + mock_overscroll_observer->WaitForUpdate(); + + blink::WebGestureEvent gesture_scroll_end( + blink::WebGestureEvent::kGestureScrollEnd, + blink::WebInputEvent::kNoModifiers, + blink::WebInputEvent::kTimeStampForTesting); + gesture_scroll_end.source_device = blink::kWebGestureDeviceTouchscreen; + gesture_scroll_end.unique_touch_event_id = 1; + gesture_scroll_end.data.scroll_end.delta_units = + blink::WebGestureEvent::ScrollUnits::kPrecisePixels; + mock_overscroll_observer->Reset(); + router->RouteGestureEvent(rwhv_root, &gesture_scroll_end, + ui::LatencyInfo(ui::SourceEventType::TOUCH)); + mock_overscroll_observer->WaitForEnd(); + + // Ensure that the method of providing the child's scroll events to the root + // does not leave the child in an invalid state. + gesture_end_observer_child->Wait(); +} +#endif // defined(USE_AURA) || defined(OS_ANDROID) + // Test that an ET_SCROLL event sent to an out-of-process iframe correctly // results in a scroll. This is only handled by RenderWidgetHostViewAura // and is needed for trackpad scrolling on Chromebooks.
diff --git a/content/browser/speech/speech_recognizer_impl.cc b/content/browser/speech/speech_recognizer_impl.cc index 03bc4cbb..ad60ac6 100644 --- a/content/browser/speech/speech_recognizer_impl.cc +++ b/content/browser/speech/speech_recognizer_impl.cc
@@ -565,8 +565,8 @@ DCHECK(recognition_engine_.get() != NULL); DCHECK(!IsCapturingAudio()); GetAudioSystem()->GetInputStreamParameters( - device_id_, base::Bind(&SpeechRecognizerImpl::OnDeviceInfo, - weak_ptr_factory_.GetWeakPtr())); + device_id_, base::BindOnce(&SpeechRecognizerImpl::OnDeviceInfo, + weak_ptr_factory_.GetWeakPtr())); listener()->OnRecognitionStart(session_id()); return STATE_PREPARING;
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index 8af8d348..aa77b714 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -46,6 +46,7 @@ #include "content/public/common/content_constants.h" #include "content/public/common/url_constants.h" #include "content/public/test/mock_render_process_host.h" +#include "content/public/test/navigation_simulator.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_utils.h" #include "content/test/test_content_browser_client.h" @@ -1041,10 +1042,7 @@ // Simulate a link click in first contents to second site. Doesn't switch // SiteInstances, because we don't intercept Blink navigations. - orig_rfh->SendRendererInitiatedNavigationRequest(url2, true); - orig_rfh->PrepareForCommit(); - contents()->TestDidNavigate(orig_rfh, 0, true, url2, - ui::PAGE_TRANSITION_TYPED); + NavigationSimulator::NavigateAndCommitFromDocument(url2, orig_rfh); SiteInstance* instance3 = contents()->GetSiteInstance(); EXPECT_EQ(instance1, instance3); EXPECT_FALSE(contents()->CrossProcessNavigationPending()); @@ -3195,18 +3193,9 @@ // Navigate the frame to another URL, which will send again // DidStartLoading and DidStopLoading messages. - { - subframe->SendRendererInitiatedNavigationRequest(foo_url, false); - subframe->PrepareForCommit(); - if (!IsBrowserSideNavigationEnabled()) { - subframe->OnMessageReceived( - FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true)); - } - subframe->SendNavigateWithTransition(10, false, foo_url, - ui::PAGE_TRANSITION_AUTO_SUBFRAME); - subframe->OnMessageReceived( - FrameHostMsg_DidStopLoading(subframe->GetRoutingID())); - } + NavigationSimulator::NavigateAndCommitFromDocument(foo_url, subframe); + subframe->OnMessageReceived( + FrameHostMsg_DidStopLoading(subframe->GetRoutingID())); // Since the main frame hasn't sent any DidStopLoading messages, it is // expected that the WebContents is still in loading state.
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc index 1647846..d094ec1f9 100644 --- a/content/renderer/gpu/render_widget_compositor.cc +++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -69,6 +69,7 @@ #include "third_party/WebKit/public/web/WebKit.h" #include "third_party/WebKit/public/web/WebSelection.h" #include "third_party/skia/include/core/SkImage.h" +#include "ui/base/ui_base_switches.h" #include "ui/gfx/color_space_switches.h" #include "ui/gfx/switches.h" #include "ui/gl/gl_switches.h" @@ -550,7 +551,7 @@ base::SharedMemory::GetHandleLimit() / 3; settings.disallow_non_exact_resource_reuse = - cmd.HasSwitch(cc::switches::kDisallowNonExactResourceReuse); + cmd.HasSwitch(switches::kDisallowNonExactResourceReuse); settings.wait_for_all_pipeline_stages_before_draw = cmd.HasSwitch(cc::switches::kRunAllCompositorStagesBeforeDraw);
diff --git a/content/shell/app/shell_main_delegate.cc b/content/shell/app/shell_main_delegate.cc index f733a47e..989b2a7 100644 --- a/content/shell/app/shell_main_delegate.cc +++ b/content/shell/app/shell_main_delegate.cc
@@ -219,7 +219,7 @@ // We want stable/baseline results when running layout tests. command_line.AppendSwitch(switches::kDisableSkiaRuntimeOpts); - command_line.AppendSwitch(cc::switches::kDisallowNonExactResourceReuse); + command_line.AppendSwitch(switches::kDisallowNonExactResourceReuse); // Unless/until WebM files are added to the media layout tests, we need to // avoid removing MP4/H264/AAC so that layout tests can run on Android.
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn index 4ced993..ddc1ae3 100644 --- a/content/test/BUILD.gn +++ b/content/test/BUILD.gn
@@ -182,6 +182,7 @@ "mock_keyboard_driver_win.h", "mock_leveldb_database.cc", "mock_leveldb_database.h", + "mock_overscroll_observer.h", "mock_permission_manager.cc", "mock_permission_manager.h", "mock_platform_notification_service.cc", @@ -370,6 +371,11 @@ } if (use_aura) { + sources += [ + "mock_overscroll_controller_delegate_aura.cc", + "mock_overscroll_controller_delegate_aura.h", + ] + deps += [ "//ui/aura:test_support", "//ui/resources:ui_test_pak", @@ -404,6 +410,11 @@ } if (is_android) { + sources += [ + "mock_overscroll_refresh_handler_android.cc", + "mock_overscroll_refresh_handler_android.h", + ] + deps += [ "//device/geolocation:geolocation_java", "//media/capture/video/android:android", @@ -934,6 +945,7 @@ "//content/shell/android:content_shell_assets", "//content/shell/android:content_shell_jni_headers", "//testing/android/native_test:native_test_support", + "//ui/android:android", ] android_manifest = "${target_gen_dir}/content_browsertests_manifest/AndroidManifest.xml"
diff --git a/content/test/data/wide_page.html b/content/test/data/wide_page.html new file mode 100644 index 0000000..4f2ae7a --- /dev/null +++ b/content/test/data/wide_page.html
@@ -0,0 +1,7 @@ +<html> +<head></head> +<body> + <div>This page is wide.</div> + <div style="min-width: 1000px">Hello</div> +</body> +</html>
diff --git a/content/test/mock_overscroll_controller_delegate_aura.cc b/content/test/mock_overscroll_controller_delegate_aura.cc new file mode 100644 index 0000000..e6f4c1e --- /dev/null +++ b/content/test/mock_overscroll_controller_delegate_aura.cc
@@ -0,0 +1,77 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/test/mock_overscroll_controller_delegate_aura.h" + +#include "content/browser/renderer_host/render_widget_host_view_aura.h" +#include "content/public/test/test_utils.h" +#include "ui/display/screen.h" + +namespace content { + +MockOverscrollControllerDelegateAura::MockOverscrollControllerDelegateAura( + RenderWidgetHostViewAura* rwhva) + : rwhva_(rwhva), + update_message_loop_runner_(new MessageLoopRunner), + end_message_loop_runner_(new MessageLoopRunner), + seen_update_(false), + overscroll_ended_(false) {} + +MockOverscrollControllerDelegateAura::~MockOverscrollControllerDelegateAura() {} + +gfx::Size MockOverscrollControllerDelegateAura::GetDisplaySize() const { + return display::Screen::GetScreen() + ->GetDisplayNearestView(rwhva_->GetNativeView()) + .size(); +} + +base::Optional<float> +MockOverscrollControllerDelegateAura::GetMaxOverscrollDelta() const { + return base::nullopt; +} + +bool MockOverscrollControllerDelegateAura::OnOverscrollUpdate(float, float) { + seen_update_ = true; + if (update_message_loop_runner_->loop_running()) + update_message_loop_runner_->Quit(); + return true; +} + +void MockOverscrollControllerDelegateAura::OnOverscrollComplete( + OverscrollMode) { + OnOverscrollEnd(); +} + +void MockOverscrollControllerDelegateAura::OnOverscrollModeChange( + OverscrollMode old_mode, + OverscrollMode new_mode, + OverscrollSource source) { + if (new_mode == OVERSCROLL_NONE) + OnOverscrollEnd(); +} + +void MockOverscrollControllerDelegateAura::WaitForUpdate() { + if (!seen_update_) + update_message_loop_runner_->Run(); +} + +void MockOverscrollControllerDelegateAura::WaitForEnd() { + if (!overscroll_ended_) + end_message_loop_runner_->Run(); +} + +void MockOverscrollControllerDelegateAura::Reset() { + update_message_loop_runner_ = new MessageLoopRunner; + end_message_loop_runner_ = new MessageLoopRunner; + seen_update_ = false; + overscroll_ended_ = false; +} + +void MockOverscrollControllerDelegateAura::OnOverscrollEnd() { + overscroll_ended_ = true; + if (end_message_loop_runner_->loop_running()) + end_message_loop_runner_->Quit(); +} + +} // namespace content
diff --git a/content/test/mock_overscroll_controller_delegate_aura.h b/content/test/mock_overscroll_controller_delegate_aura.h new file mode 100644 index 0000000..bcd2561 --- /dev/null +++ b/content/test/mock_overscroll_controller_delegate_aura.h
@@ -0,0 +1,53 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_TEST_MOCK_OVERSCROLL_CONTROLLER_DELEGATE_AURA_H_ +#define CONTENT_TEST_MOCK_OVERSCROLL_CONTROLLER_DELEGATE_AURA_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "content/browser/renderer_host/overscroll_controller_delegate.h" +#include "content/test/mock_overscroll_observer.h" + +namespace content { + +class MessageLoopRunner; +class RenderWidgetHostViewAura; + +// Receives overscroll gesture updates from the aura overscroll controller. +class MockOverscrollControllerDelegateAura + : public OverscrollControllerDelegate, + public MockOverscrollObserver { + public: + MockOverscrollControllerDelegateAura(RenderWidgetHostViewAura* rwhva); + ~MockOverscrollControllerDelegateAura() override; + + // OverscrollControllerDelegate: + gfx::Size GetDisplaySize() const override; + base::Optional<float> GetMaxOverscrollDelta() const override; + bool OnOverscrollUpdate(float, float) override; + void OnOverscrollComplete(OverscrollMode) override; + void OnOverscrollModeChange(OverscrollMode old_mode, + OverscrollMode new_mode, + OverscrollSource source) override; + + // MockOverscrollObserver: + void WaitForUpdate() override; + void WaitForEnd() override; + void Reset() override; + + private: + void OnOverscrollEnd(); + + RenderWidgetHostViewAura* rwhva_; + scoped_refptr<MessageLoopRunner> update_message_loop_runner_; + scoped_refptr<MessageLoopRunner> end_message_loop_runner_; + bool seen_update_; + bool overscroll_ended_; + DISALLOW_COPY_AND_ASSIGN(MockOverscrollControllerDelegateAura); +}; + +} // namespace content + +#endif // CONTENT_TEST_MOCK_OVERSCROLL_CONTROLLER_DELEGATE_AURA_H_
diff --git a/content/test/mock_overscroll_observer.h b/content/test/mock_overscroll_observer.h new file mode 100644 index 0000000..4d3f5f5 --- /dev/null +++ b/content/test/mock_overscroll_observer.h
@@ -0,0 +1,23 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_TEST_MOCK_OVERSCROLL_OBSERVER_H_ +#define CONTENT_TEST_MOCK_OVERSCROLL_OBSERVER_H_ + +namespace content { + +// An interface for tests to use MockOverscrollControllerDelegateAura and +// MockOverscrollRefreshHandlerAndroid. +class MockOverscrollObserver { + public: + MockOverscrollObserver() {} + virtual ~MockOverscrollObserver() {} + virtual void WaitForUpdate() = 0; + virtual void WaitForEnd() = 0; + virtual void Reset() = 0; +}; + +} // namespace content + +#endif // CONTENT_TEST_MOCK_OVERSCROLL_OBSERVER_H_
diff --git a/content/test/mock_overscroll_refresh_handler_android.cc b/content/test/mock_overscroll_refresh_handler_android.cc new file mode 100644 index 0000000..7337058 --- /dev/null +++ b/content/test/mock_overscroll_refresh_handler_android.cc
@@ -0,0 +1,65 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/test/mock_overscroll_refresh_handler_android.h" + +#include "content/public/test/test_utils.h" + +namespace content { + +MockOverscrollRefreshHandlerAndroid::MockOverscrollRefreshHandlerAndroid() + : ui::OverscrollRefreshHandler(nullptr) {} + +MockOverscrollRefreshHandlerAndroid::~MockOverscrollRefreshHandlerAndroid() {} + +bool MockOverscrollRefreshHandlerAndroid::PullStart() { + // The first GestureScrollUpdate starts the pull, but does not update the + // pull. For the purpose of testing, we'll be consistent with aura + // overscroll and consider this an update. + OnPullUpdate(); + return true; +} + +void MockOverscrollRefreshHandlerAndroid::PullUpdate(float) { + OnPullUpdate(); +} + +void MockOverscrollRefreshHandlerAndroid::PullRelease(bool) { + OnPullEnd(); +} + +void MockOverscrollRefreshHandlerAndroid::PullReset() { + OnPullEnd(); +} + +void MockOverscrollRefreshHandlerAndroid::WaitForUpdate() { + if (!seen_update_) + update_message_loop_runner_->Run(); +} + +void MockOverscrollRefreshHandlerAndroid::WaitForEnd() { + if (!pull_ended_) + end_message_loop_runner_->Run(); +} + +void MockOverscrollRefreshHandlerAndroid::Reset() { + update_message_loop_runner_ = new MessageLoopRunner; + end_message_loop_runner_ = new MessageLoopRunner; + seen_update_ = false; + pull_ended_ = false; +} + +void MockOverscrollRefreshHandlerAndroid::OnPullUpdate() { + seen_update_ = true; + if (update_message_loop_runner_->loop_running()) + update_message_loop_runner_->Quit(); +} + +void MockOverscrollRefreshHandlerAndroid::OnPullEnd() { + pull_ended_ = true; + if (end_message_loop_runner_->loop_running()) + end_message_loop_runner_->Quit(); +} + +} // namespace content
diff --git a/content/test/mock_overscroll_refresh_handler_android.h b/content/test/mock_overscroll_refresh_handler_android.h new file mode 100644 index 0000000..e74cdb07 --- /dev/null +++ b/content/test/mock_overscroll_refresh_handler_android.h
@@ -0,0 +1,48 @@ +// Copyright (c) 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_TEST_MOCK_OVERSCROLL_REFRESH_HANDLER_ANDROID_H_ +#define CONTENT_TEST_MOCK_OVERSCROLL_REFRESH_HANDLER_ANDROID_H_ + +#include "base/macros.h" +#include "base/memory/ref_counted.h" +#include "content/test/mock_overscroll_observer.h" +#include "ui/android/overscroll_refresh_handler.h" + +namespace content { + +class MessageLoopRunner; + +// Receives overscroll gesture updates from the android overscroll controller. +class MockOverscrollRefreshHandlerAndroid : public ui::OverscrollRefreshHandler, + public MockOverscrollObserver { + public: + MockOverscrollRefreshHandlerAndroid(); + ~MockOverscrollRefreshHandlerAndroid() override; + + // ui::OverscrollRefreshHandler: + bool PullStart() override; + void PullUpdate(float) override; + void PullRelease(bool) override; + void PullReset() override; + + // MockOverscrollObserver: + void WaitForUpdate() override; + void WaitForEnd() override; + void Reset() override; + + private: + void OnPullUpdate(); + void OnPullEnd(); + + scoped_refptr<MessageLoopRunner> update_message_loop_runner_; + scoped_refptr<MessageLoopRunner> end_message_loop_runner_; + bool seen_update_; + bool pull_ended_; + DISALLOW_COPY_AND_ASSIGN(MockOverscrollRefreshHandlerAndroid); +}; + +} // namespace content + +#endif // CONTENT_TEST_MOCK_OVERSCROLL_REFRESH_HANDLER_ANDROID_H_
diff --git a/extensions/renderer/bindings/api_event_handler_unittest.cc b/extensions/renderer/bindings/api_event_handler_unittest.cc index 471f580..ac9dbb12 100644 --- a/extensions/renderer/bindings/api_event_handler_unittest.cc +++ b/extensions/renderer/bindings/api_event_handler_unittest.cc
@@ -597,8 +597,9 @@ EXPECT_EQ("[42]", GetStringPropertyFromObject(context->Global(), context, "eventArgs")); ASSERT_EQ(1u, logged_errors.size()); - EXPECT_EQ("Error in event handler: Uncaught Error: Event handler error", - logged_errors[0]); + EXPECT_THAT(logged_errors[0], + testing::StartsWith("Error in event handler: Error: " + "Event handler error")); } // Tests being notified as listeners are added or removed from events.
diff --git a/extensions/renderer/bindings/api_request_handler_unittest.cc b/extensions/renderer/bindings/api_request_handler_unittest.cc index a5d365a8..cb7738e8 100644 --- a/extensions/renderer/bindings/api_request_handler_unittest.cc +++ b/extensions/renderer/bindings/api_request_handler_unittest.cc
@@ -523,7 +523,8 @@ // by the exception handler. EXPECT_FALSE(outer_try_catch.HasCaught()); ASSERT_TRUE(logged_error); - EXPECT_EQ("Error handling response: Uncaught Error: hello", *logged_error); + EXPECT_THAT(*logged_error, + testing::StartsWith("Error handling response: Error: hello")); } } // namespace extensions
diff --git a/extensions/renderer/bindings/event_emitter_unittest.cc b/extensions/renderer/bindings/event_emitter_unittest.cc index 5414e84..2ef4da0 100644 --- a/extensions/renderer/bindings/event_emitter_unittest.cc +++ b/extensions/renderer/bindings/event_emitter_unittest.cc
@@ -12,6 +12,7 @@ #include "extensions/renderer/bindings/api_event_listeners.h" #include "extensions/renderer/bindings/exception_handler.h" #include "gin/handle.h" +#include "testing/gmock/include/gmock/gmock.h" namespace extensions { namespace { @@ -126,7 +127,8 @@ V8ToString(dispatch_result, context)); ASSERT_EQ(1u, logged_errors.size()); - EXPECT_EQ("Error in event handler: Uncaught Error: hahaha", logged_errors[0]); + EXPECT_THAT(logged_errors[0], + testing::StartsWith("Error in event handler: Error: hahaha")); } } // namespace extensions
diff --git a/extensions/renderer/bindings/exception_handler.cc b/extensions/renderer/bindings/exception_handler.cc index 433fd706..899faa3 100644 --- a/extensions/renderer/bindings/exception_handler.cc +++ b/extensions/renderer/bindings/exception_handler.cc
@@ -57,11 +57,22 @@ v8::Isolate* isolate = context->GetIsolate(); v8::HandleScope handle_scope(isolate); - v8::Local<v8::Message> v8_message = try_catch->Message(); + v8::Local<v8::Value> message_value; + { + v8::TryCatch inner_try_catch(context->GetIsolate()); + inner_try_catch.SetVerbose(true); + v8::Local<v8::Value> stack_trace_value; + if (try_catch->StackTrace(context).ToLocal(&stack_trace_value)) { + message_value = stack_trace_value; + } else if (!try_catch->Message().IsEmpty()) { + message_value = try_catch->Message()->Get(); + } + } + std::string full_message = - !v8_message.IsEmpty() + !message_value.IsEmpty() ? base::StringPrintf("%s: %s", message.c_str(), - gin::V8ToString(v8_message->Get()).c_str()) + gin::V8ToString(message_value).c_str()) : message; HandleException(context, full_message, try_catch->Exception()); try_catch->Reset(); // Reset() to avoid handling the error more than once.
diff --git a/extensions/renderer/bindings/exception_handler_unittest.cc b/extensions/renderer/bindings/exception_handler_unittest.cc index e79b351d..647620371 100644 --- a/extensions/renderer/bindings/exception_handler_unittest.cc +++ b/extensions/renderer/bindings/exception_handler_unittest.cc
@@ -12,6 +12,7 @@ #include "extensions/renderer/bindings/api_binding_test.h" #include "extensions/renderer/bindings/api_binding_test_util.h" #include "gin/converter.h" +#include "testing/gmock/include/gmock/gmock.h" namespace extensions { @@ -51,7 +52,7 @@ ThrowException(context, "new Error('some error')", &handler); ASSERT_TRUE(logged_error); - EXPECT_EQ("handled: Uncaught Error: some error", *logged_error); + EXPECT_THAT(*logged_error, testing::StartsWith("handled: Error: some error")); } TEST_F(ExceptionHandlerTest, PerContextHandlers) { @@ -73,9 +74,9 @@ handler.SetHandlerForContext(context_a, custom_handler); ThrowException(context_a, "new Error('context a error')", &handler); EXPECT_FALSE(logged_error); - EXPECT_EQ("\"handled: Uncaught Error: context a error\"", - GetStringPropertyFromObject(context_a->Global(), context_a, - "loggedMessage")); + EXPECT_THAT(GetStringPropertyFromObject(context_a->Global(), context_a, + "loggedMessage"), + testing::StartsWith("\"handled: Error: context a error")); EXPECT_EQ("\"context a error\"", GetStringPropertyFromObject(context_a->Global(), context_a, "loggedExceptionMessage")); @@ -94,7 +95,8 @@ ThrowException(context_b, "new Error('context b error')", &handler); ASSERT_TRUE(logged_error); - EXPECT_EQ("handled: Uncaught Error: context b error", *logged_error); + EXPECT_THAT(*logged_error, + testing::StartsWith("handled: Error: context b error")); EXPECT_EQ("undefined", GetStringPropertyFromObject( context_a->Global(), context_a, "loggedMessage")); EXPECT_EQ("undefined", @@ -141,4 +143,67 @@ "loggedException")); } +TEST_F(ExceptionHandlerTest, StackTraces) { + v8::HandleScope handle_scope(isolate()); + v8::Local<v8::Context> context = MainContext(); + + base::Optional<std::string> logged_error; + ExceptionHandler handler(base::Bind(&PopulateError, &logged_error), + base::Bind(&RunFunctionOnGlobalAndIgnoreResult)); + + { + v8::TryCatch try_catch(isolate()); + v8::Local<v8::Script> script = + v8::Script::Compile(context, + gin::StringToV8(context->GetIsolate(), + "throw new Error('simple');")) + .ToLocalChecked(); + script->Run(); + ASSERT_TRUE(try_catch.HasCaught()); + handler.HandleException(context, "handled", &try_catch); + + ASSERT_TRUE(logged_error); + EXPECT_EQ("handled: Error: simple\n at <anonymous>:1:7", *logged_error); + } + + logged_error.reset(); + + { + v8::TryCatch try_catch(isolate()); + v8::Local<v8::Function> throw_error_function = FunctionFromString( + context, "(function() { throw new Error('function'); })"); + ignore_result(throw_error_function->Call(context, v8::Undefined(isolate()), + 0, nullptr)); + ASSERT_TRUE(try_catch.HasCaught()); + handler.HandleException(context, "handled", &try_catch); + ASSERT_TRUE(logged_error); + EXPECT_EQ("handled: Error: function\n at <anonymous>:1:21", + *logged_error); + } + + logged_error.reset(); + + { + v8::TryCatch try_catch(isolate()); + const char kNestedCall[] = + "function throwError() { throw new Error('nested'); }\n" + "function callThrowError() { throwError(); }\n" + "callThrowError()\n"; + v8::Local<v8::Script> script = + v8::Script::Compile(context, + gin::StringToV8(context->GetIsolate(), kNestedCall)) + .ToLocalChecked(); + script->Run(); + ASSERT_TRUE(try_catch.HasCaught()); + handler.HandleException(context, "handled", &try_catch); + ASSERT_TRUE(logged_error); + const char kExpectedError[] = + "handled: Error: nested\n" + " at throwError (<anonymous>:1:31)\n" + " at callThrowError (<anonymous>:2:29)\n" + " at <anonymous>:3:1"; + EXPECT_EQ(kExpectedError, *logged_error); + } +} + } // namespace extensions
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 9e04b94b..0bb39bb 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -686,6 +686,7 @@ // Initialize or re-initialize the shader translator. bool InitializeShaderTranslator(); + void DestroyShaderTranslator(); void UpdateCapabilities(); @@ -1754,7 +1755,7 @@ GLuint renderbuffer, GLenum format); // Wrapper for glReleaseShaderCompiler. - void DoReleaseShaderCompiler() { } + void DoReleaseShaderCompiler(); // Wrappers for glSamplerParameter functions. void DoSamplerParameterf(GLuint client_id, GLenum pname, GLfloat param); @@ -2375,6 +2376,7 @@ // if not returning an error. error::Error current_decoder_error_; + bool has_fragment_precision_high_ = false; scoped_refptr<ShaderTranslatorInterface> vertex_translator_; scoped_refptr<ShaderTranslatorInterface> fragment_translator_; @@ -3534,9 +3536,12 @@ features().khr_robustness || features().ext_robustness; - if (!InitializeShaderTranslator()) { - return false; - } + GLint range[2] = {0, 0}; + GLint precision = 0; + QueryShaderPrecisionFormat(gl_version_info(), GL_FRAGMENT_SHADER, + GL_HIGH_FLOAT, range, &precision); + has_fragment_precision_high_ = + PrecisionMeetsSpecForHighpFloat(range[0], range[1], precision); GLint viewport_params[4] = { 0 }; glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport_params); @@ -3898,6 +3903,10 @@ if (feature_info_->disable_shader_translator()) { return true; } + if (vertex_translator_ || fragment_translator_) { + DCHECK(vertex_translator_ && fragment_translator_); + return true; + } ShBuiltInResources resources; sh::InitBuiltInResources(&resources); resources.MaxVertexAttribs = group_->max_vertex_attribs(); @@ -3924,12 +3933,7 @@ resources.MinProgramTexelOffset = group_->min_program_texel_offset(); } - GLint range[2] = { 0, 0 }; - GLint precision = 0; - QueryShaderPrecisionFormat(gl_version_info(), GL_FRAGMENT_SHADER, - GL_HIGH_FLOAT, range, &precision); - resources.FragmentPrecisionHigh = - PrecisionMeetsSpecForHighpFloat(range[0], range[1], precision); + resources.FragmentPrecisionHigh = has_fragment_precision_high_; ShShaderSpec shader_spec; switch (feature_info_->context_type()) { @@ -4048,6 +4052,11 @@ return true; } +void GLES2DecoderImpl::DestroyShaderTranslator() { + vertex_translator_ = nullptr; + fragment_translator_ = nullptr; +} + bool GLES2DecoderImpl::GenBuffersHelper(GLsizei n, const GLuint* client_ids) { for (GLsizei ii = 0; ii < n; ++ii) { if (GetBuffer(client_ids[ii])) { @@ -4909,8 +4918,7 @@ // Need to release these before releasing |group_| which may own the // ShaderTranslatorCache. - fragment_translator_ = NULL; - vertex_translator_ = NULL; + DestroyShaderTranslator(); // Destroy the GPU Tracer which may own some in process GPU Timings. if (gpu_tracer_) { @@ -8748,6 +8756,10 @@ pixel[2] == 0xFF); } +void GLES2DecoderImpl::DoReleaseShaderCompiler() { + DestroyShaderTranslator(); +} + void GLES2DecoderImpl::DoRenderbufferStorage( GLenum target, GLenum internalformat, GLsizei width, GLsizei height) { Renderbuffer* renderbuffer = @@ -10583,6 +10595,9 @@ scoped_refptr<ShaderTranslatorInterface> GLES2DecoderImpl::GetTranslator( GLenum type) { + if (!InitializeShaderTranslator()) { + return nullptr; + } return type == GL_VERTEX_SHADER ? vertex_translator_ : fragment_translator_; } @@ -15898,7 +15913,7 @@ frag_depth_explicitly_enabled_ |= desire_frag_depth; draw_buffers_explicitly_enabled_ |= desire_draw_buffers; shader_texture_lod_explicitly_enabled_ |= desire_shader_texture_lod; - InitializeShaderTranslator(); + DestroyShaderTranslator(); } if (feature_str.find("GL_CHROMIUM_color_buffer_float_rgba ") !=
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index bda9206..6aa7196 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -1917,7 +1917,8 @@ TestHelper::SetShaderStates(gl_.get(), GetShader(vertex_shader_client_id), true, nullptr, nullptr, &shader_language_version_, - nullptr, nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr); OutputVariableList frag_output_variable_list; frag_output_variable_list.push_back(TestHelper::ConstructOutputVariable( @@ -1927,7 +1928,7 @@ TestHelper::SetShaderStates(gl_.get(), GetShader(fragment_shader_client_id), true, nullptr, nullptr, &shader_language_version_, nullptr, nullptr, nullptr, nullptr, - &frag_output_variable_list); + &frag_output_variable_list, nullptr); cmds::AttachShader attach_cmd; attach_cmd.Init(program_client_id, vertex_shader_client_id);
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc index b2c2f001..f51c5a3 100644 --- a/gpu/command_buffer/service/memory_program_cache_unittest.cc +++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -149,11 +149,11 @@ TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true, nullptr, nullptr, nullptr, &vertex_attrib_map, &vertex_uniform_map, &vertex_varying_map, - nullptr, &vertex_output_variable_list); - TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true, nullptr, - nullptr, nullptr, &fragment_attrib_map, - &fragment_uniform_map, &fragment_varying_map, - nullptr, &fragment_output_variable_list); + nullptr, &vertex_output_variable_list, nullptr); + TestHelper::SetShaderStates( + gl_.get(), fragment_shader_, true, nullptr, nullptr, nullptr, + &fragment_attrib_map, &fragment_uniform_map, &fragment_varying_map, + nullptr, &fragment_output_variable_list, nullptr); } void SetExpectationsForSaveLinkedProgram(
diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h index 25c23f0..1f88ea6 100644 --- a/gpu/command_buffer/service/mocks.h +++ b/gpu/command_buffer/service/mocks.h
@@ -109,8 +109,9 @@ VaryingMap* varying_map, InterfaceBlockMap* interface_block_map, OutputVariableList* output_variable_list)); - MOCK_CONST_METHOD0( - GetStringForOptionsThatWouldAffectCompilation, std::string()); + MOCK_CONST_METHOD0(GetStringForOptionsThatWouldAffectCompilation, + OptionsAffectingCompilationString*()); + private: ~MockShaderTranslator() override; };
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index e0269249..101d2784 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -29,6 +29,7 @@ using ::testing::_; using ::testing::DoAll; +using ::testing::Exactly; using ::testing::InSequence; using ::testing::MatcherCast; using ::testing::Pointee; @@ -437,11 +438,11 @@ TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, shader_version, &vertex_attrib_map, &vertex_uniform_map, &vertex_varying_map, - nullptr, &vertex_output_variable_list); + nullptr, &vertex_output_variable_list, nullptr); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, shader_version, &frag_attrib_map, &frag_uniform_map, &frag_varying_map, nullptr, - &frag_output_variable_list); + &frag_output_variable_list, nullptr); // Set up program Program* program = @@ -942,13 +943,13 @@ ASSERT_TRUE(vshader != NULL); TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, nullptr, &attrib_map, &uniform_map, &varying_map, - nullptr, &output_variable_list); + nullptr, &output_variable_list, nullptr); Shader* fshader = shader_manager_.CreateShader( kFragmentShaderClientId, kFragmentShaderServiceId, GL_FRAGMENT_SHADER); ASSERT_TRUE(fshader != NULL); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, &attrib_map, &uniform_map, &varying_map, - nullptr, &output_variable_list); + nullptr, &output_variable_list, nullptr); static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = { { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, { kAttrib2Name, kAttrib2Size, kAttrib2BadType, kAttrib2Location, }, @@ -1612,7 +1613,7 @@ // Set Status TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, nullptr, &attrib_map, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); // Check attrib infos got copied. for (AttributeMap::const_iterator it = attrib_map.begin(); it != attrib_map.end(); ++it) { @@ -1627,7 +1628,7 @@ } TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, &attrib_map, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); // Set up program Program* program = manager_->CreateProgram(kClientProgramId, kServiceProgramId); @@ -1695,10 +1696,10 @@ // Set Status TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, nullptr, nullptr, &vertex_uniform_map, nullptr, - nullptr, nullptr); + nullptr, nullptr, nullptr); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, &frag_uniform_map, nullptr, - nullptr, nullptr); + nullptr, nullptr, nullptr); // Set up program Program* program = manager_->CreateProgram(kClientProgramId, kServiceProgramId); @@ -1817,7 +1818,7 @@ kVertexShaderClientId, kVertexShaderServiceId, GL_VERTEX_SHADER); TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); Shader* fshader = shader_manager_.CreateShader( kFragmentShaderClientId, kFragmentShaderServiceId, GL_FRAGMENT_SHADER); ASSERT_TRUE(vshader && fshader); @@ -1830,7 +1831,7 @@ { // No outputs. TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - nullptr); + nullptr, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0u, program->fragment_output_type_mask()); EXPECT_EQ(0u, program->fragment_output_written_mask()); @@ -1844,7 +1845,7 @@ fragment_outputs.push_back(var); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &fragment_outputs); + &fragment_outputs, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0x3u, program->fragment_output_type_mask()); EXPECT_EQ(0x3u, program->fragment_output_written_mask()); @@ -1858,7 +1859,7 @@ fragment_outputs.push_back(var); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &fragment_outputs); + &fragment_outputs, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0xFFFFu, program->fragment_output_type_mask()); EXPECT_EQ(0xFFFFu, program->fragment_output_written_mask()); @@ -1876,7 +1877,7 @@ fragment_outputs.push_back(var); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &fragment_outputs); + &fragment_outputs, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0x3u, program->fragment_output_type_mask()); EXPECT_EQ(0x3u, program->fragment_output_written_mask()); @@ -1890,7 +1891,7 @@ fragment_outputs.push_back(var); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &fragment_outputs); + &fragment_outputs, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0x2u, program->fragment_output_type_mask()); EXPECT_EQ(0x3u, program->fragment_output_written_mask()); @@ -1904,7 +1905,7 @@ fragment_outputs.push_back(var); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &fragment_outputs); + &fragment_outputs, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0x2u, program->fragment_output_type_mask()); EXPECT_EQ(0x3u, program->fragment_output_written_mask()); @@ -1922,7 +1923,7 @@ fragment_outputs.push_back(var); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &fragment_outputs); + &fragment_outputs, nullptr); EXPECT_TRUE(LinkAsExpected(program, true)); EXPECT_EQ(0xF1u, program->fragment_output_type_mask()); EXPECT_EQ(0xF3u, program->fragment_output_written_mask()); @@ -2201,6 +2202,13 @@ TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true); } + void SetShadersCompiled(const std::string& compilation_options_string) { + TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true, + compilation_options_string); + TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true, + compilation_options_string); + } + void SetProgramCached() { cache_->LinkedProgramCacheSuccess( vertex_shader_->source(), fragment_shader_->source(), @@ -2280,6 +2288,16 @@ nullptr, 0, service_program_id); } + void SetExpectationsForProgramNotLoaded() { + EXPECT_CALL(*cache_.get(), + LoadLinkedProgram( + program_->service_id(), vertex_shader_, fragment_shader_, + &program_->bind_attrib_location_map(), + program_->effective_transform_feedback_varyings(), + program_->effective_transform_feedback_buffer_mode(), _)) + .Times(Exactly(0)); + } + void SetExpectationsForProgramLink() { SetExpectationsForProgramLink(kServiceProgramId); } @@ -2368,6 +2386,17 @@ EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed, this)); } +TEST_F(ProgramManagerWithCacheTest, RelinkOnChangedCompileOptions) { + SetShadersCompiled("a"); + SetProgramCached(); + SetExpectationsForProgramCached(); + + SetShadersCompiled("b"); + SetExpectationsForProgramLink(); + SetExpectationsForProgramNotLoaded(); + EXPECT_TRUE(program_->Link(NULL, Program::kCountOnlyStaticallyUsed, this)); +} + class ProgramManagerWithPathRenderingTest : public ProgramManagerWithShaderTest, public testing::WithParamInterface< @@ -2454,10 +2483,10 @@ kFragmentInput3StaticUse, kFragmentInput3Name); TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, &varying_map, nullptr, - nullptr); + nullptr, nullptr); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, &varying_map, nullptr, - nullptr); + nullptr, nullptr); Program* program = manager_->CreateProgram(kClientProgramId, kServiceProgramId); ASSERT_TRUE(program != NULL);
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc index 8a77b519..77e0df23e 100644 --- a/gpu/command_buffer/service/shader_manager.cc +++ b/gpu/command_buffer/service/shader_manager.cc
@@ -51,6 +51,10 @@ TranslatedShaderSourceType type) { shader_state_ = kShaderStateCompileRequested; translator_ = translator; + if (translator_) { + options_affecting_compilation_ = + translator_->GetStringForOptionsThatWouldAffectCompilation(); + } source_type_ = type; last_compiled_source_ = source_; } @@ -121,6 +125,9 @@ << "\n--translated-shader--\n" << source_for_driver << "\n--info-log--\n" << log_info_; } + + // Translator is no longer required and can be released + translator_ = nullptr; } void Shader::RefreshTranslatedShaderSource() {
diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h index c9c2df3..4df84f0 100644 --- a/gpu/command_buffer/service/shader_manager.h +++ b/gpu/command_buffer/service/shader_manager.h
@@ -85,9 +85,8 @@ } std::string last_compiled_signature() const { - if (translator_.get()) { - return last_compiled_source_ + - translator_->GetStringForOptionsThatWouldAffectCompilation(); + if (options_affecting_compilation_) { + return last_compiled_source_ + options_affecting_compilation_->data; } return last_compiled_source_; } @@ -235,6 +234,8 @@ // Translator to use, set when shader was last requested to be compiled. scoped_refptr<ShaderTranslatorInterface> translator_; + scoped_refptr<OptionsAffectingCompilationString> + options_affecting_compilation_; // True if compilation succeeded. bool valid_;
diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc index bbf1470..9c552cb 100644 --- a/gpu/command_buffer/service/shader_manager_unittest.cc +++ b/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -220,9 +220,10 @@ kInterfaceBlock1Name, kInterfaceBlock1InstanceName, interface_block1_fields); - TestHelper::SetShaderStates( - gl_.get(), shader1, true, &kLog, &kTranslatedSource, nullptr, &attrib_map, - &uniform_map, &varying_map, &interface_block_map, &output_variable_list); + TestHelper::SetShaderStates(gl_.get(), shader1, true, &kLog, + &kTranslatedSource, nullptr, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, + &output_variable_list, nullptr); EXPECT_TRUE(shader1->valid()); // When compilation succeeds, no log is recorded. @@ -325,9 +326,10 @@ } // Compile failure case. - TestHelper::SetShaderStates( - gl_.get(), shader1, false, &kLog, &kTranslatedSource, nullptr, - &attrib_map, &uniform_map, &varying_map, nullptr, &output_variable_list); + TestHelper::SetShaderStates(gl_.get(), shader1, false, &kLog, + &kTranslatedSource, nullptr, &attrib_map, + &uniform_map, &varying_map, nullptr, + &output_variable_list, nullptr); EXPECT_FALSE(shader1->valid()); EXPECT_STREQ(kLog.c_str(), shader1->log_info().c_str()); EXPECT_STREQ("", shader1->translated_source().c_str());
diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc index 40f45e8..a22b679 100644 --- a/gpu/command_buffer/service/shader_translator.cc +++ b/gpu/command_buffer/service/shader_translator.cc
@@ -185,6 +185,14 @@ break; } + if (compiler_) { + options_affecting_compilation_ = + base::MakeRefCounted<OptionsAffectingCompilationString>( + std::string(":CompileOptions:" + + base::Uint64ToString(GetCompileOptions())) + + sh::GetBuiltInResourcesString(compiler_)); + } + return compiler_ != NULL; } @@ -237,12 +245,9 @@ return success; } -std::string ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation() - const { - DCHECK(compiler_ != NULL); - return std::string(":CompileOptions:" + - base::Uint64ToString(GetCompileOptions())) + - sh::GetBuiltInResourcesString(compiler_); +OptionsAffectingCompilationString* +ShaderTranslator::GetStringForOptionsThatWouldAffectCompilation() const { + return options_affecting_compilation_.get(); } void ShaderTranslator::AddDestructionObserver(
diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h index 43ae7df7..a0a9c90e 100644 --- a/gpu/command_buffer/service/shader_translator.h +++ b/gpu/command_buffer/service/shader_translator.h
@@ -27,6 +27,7 @@ typedef base::hash_map<std::string, sh::Uniform> UniformMap; typedef base::hash_map<std::string, sh::Varying> VaryingMap; typedef base::hash_map<std::string, sh::InterfaceBlock> InterfaceBlockMap; +typedef base::RefCountedData<std::string> OptionsAffectingCompilationString; // Translates a GLSL ES 2.0 shader to desktop GLSL shader, or just // validates GLSL ES 2.0 shaders on a true GLSL ES implementation. @@ -61,7 +62,8 @@ // Return a string that is unique for a specfic set of options that would // possibly affect compilation. - virtual std::string GetStringForOptionsThatWouldAffectCompilation() const = 0; + virtual OptionsAffectingCompilationString* + GetStringForOptionsThatWouldAffectCompilation() const = 0; protected: virtual ~ShaderTranslatorInterface() {} @@ -111,7 +113,8 @@ InterfaceBlockMap* interface_block_map, OutputVariableList* output_variable_list) const override; - std::string GetStringForOptionsThatWouldAffectCompilation() const override; + OptionsAffectingCompilationString* + GetStringForOptionsThatWouldAffectCompilation() const override; void AddDestructionObserver(DestructionObserver* observer); void RemoveDestructionObserver(DestructionObserver* observer); @@ -123,6 +126,8 @@ ShHandle compiler_; ShCompileOptions compile_options_; + scoped_refptr<OptionsAffectingCompilationString> + options_affecting_compilation_; base::ObserverList<DestructionObserver> destruction_observers_; };
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc index d9e0a418..6d2eb30 100644 --- a/gpu/command_buffer/service/shader_translator_unittest.cc +++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -418,13 +418,13 @@ false)); std::string options_1( - translator_1->GetStringForOptionsThatWouldAffectCompilation()); + translator_1->GetStringForOptionsThatWouldAffectCompilation()->data); std::string options_2( - translator_1->GetStringForOptionsThatWouldAffectCompilation()); + translator_1->GetStringForOptionsThatWouldAffectCompilation()->data); std::string options_3( - translator_2->GetStringForOptionsThatWouldAffectCompilation()); + translator_2->GetStringForOptionsThatWouldAffectCompilation()->data); std::string options_4( - translator_3->GetStringForOptionsThatWouldAffectCompilation()); + translator_3->GetStringForOptionsThatWouldAffectCompilation()->data); EXPECT_EQ(options_1, options_2); EXPECT_NE(options_1, options_3);
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index 4b56f76..85315f05 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc
@@ -1119,7 +1119,8 @@ const UniformMap* const expected_uniform_map, const VaryingMap* const expected_varying_map, const InterfaceBlockMap* const expected_interface_block_map, - const OutputVariableList* const expected_output_variable_list) { + const OutputVariableList* const expected_output_variable_list, + OptionsAffectingCompilationString* options_affecting_compilation) { const std::string empty_log_info; const std::string* log_info = (expected_log_info && !expected_valid) ? expected_log_info : &empty_log_info; @@ -1167,6 +1168,9 @@ SetArgPointee<7>(*interface_block_map), SetArgPointee<8>(*output_variable_list), Return(expected_valid))) .RetiresOnSaturation(); + EXPECT_CALL(*mock_translator, GetStringForOptionsThatWouldAffectCompilation()) + .WillOnce(Return(options_affecting_compilation)) + .RetiresOnSaturation(); if (expected_valid) { EXPECT_CALL(*gl, ShaderSource(shader->service_id(), 1, _, NULL)) .Times(1) @@ -1188,7 +1192,20 @@ Shader* shader, bool valid) { SetShaderStates(gl, shader, valid, nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr); + nullptr, nullptr, nullptr, nullptr, nullptr); +} + +// static +void TestHelper::SetShaderStates( + ::gl::MockGLInterface* gl, + Shader* shader, + bool valid, + const std::string& options_affecting_compilation) { + scoped_refptr<OptionsAffectingCompilationString> options = + base::MakeRefCounted<OptionsAffectingCompilationString>( + options_affecting_compilation); + SetShaderStates(gl, shader, valid, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, options.get()); } // static
diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h index f138507..7334064 100644 --- a/gpu/command_buffer/service/test_helper.h +++ b/gpu/command_buffer/service/test_helper.h
@@ -197,12 +197,18 @@ const UniformMap* const expected_uniform_map, const VaryingMap* const expected_varying_map, const InterfaceBlockMap* const expected_interface_block_map, - const OutputVariableList* const expected_output_variable_list); + const OutputVariableList* const expected_output_variable_list, + OptionsAffectingCompilationString* options_affecting_compilation); static void SetShaderStates(::gl::MockGLInterface* gl, Shader* shader, bool valid); + static void SetShaderStates(::gl::MockGLInterface* gl, + Shader* shader, + bool valid, + const std::string& options_affecting_compilation); + static sh::Attribute ConstructAttribute( GLenum type, GLint array_size, GLenum precision, bool static_use, const std::string& name);
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn index c51404ca..67178ce 100644 --- a/ios/chrome/app/BUILD.gn +++ b/ios/chrome/app/BUILD.gn
@@ -294,6 +294,7 @@ } extra_substitutions = [ + "CONTENT_WIDGET_EXTENSION_BUNDLE_ID=$chromium_bundle_id.ContentTodayExtension", "CHROMIUM_BUNDLE_ID=$chromium_bundle_id", "CHROMIUM_HANDOFF_ID=$chromium_handoff_id", "CHROMIUM_SHORT_NAME=$chromium_short_name",
diff --git a/ios/chrome/app/resources/Info.plist b/ios/chrome/app/resources/Info.plist index 2a0bb7b..0e35e4e6 100644 --- a/ios/chrome/app/resources/Info.plist +++ b/ios/chrome/app/resources/Info.plist
@@ -2,6 +2,8 @@ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> + <key>UIApplicationShortcutWidget</key> + <string>${IOS_BUNDLE_ID_PREFIX}.${CONTENT_WIDGET_EXTENSION_BUNDLE_ID}</string> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleDisplayName</key>
diff --git a/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni b/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni index 7623cb51..9778832 100644 --- a/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni +++ b/ios/chrome/test/earl_grey/chrome_ios_eg_test.gni
@@ -139,6 +139,7 @@ "CHROMIUM_URL_SCHEME_4=$url_channel_scheme", "EG_MAIN_APPLICATION_DELEGATE=$_eg_main_application_delegate", "SSOAUTH_URL_SCHEME=$url_ssoauth_scheme", + "CONTENT_WIDGET_EXTENSION_BUNDLE_ID=$chromium_bundle_id.ContentTodayExtension", ] if (ios_automatically_manage_certs) { # Use the same bundle identifier for EarlGrey tests as for unit tests
diff --git a/ios/clean/chrome/app/BUILD.gn b/ios/clean/chrome/app/BUILD.gn index e5d414ba..3e49a59 100644 --- a/ios/clean/chrome/app/BUILD.gn +++ b/ios/clean/chrome/app/BUILD.gn
@@ -52,6 +52,7 @@ bundle_deps = [ "//ios/chrome/app/resources" ] extra_substitutions = [ + "CONTENT_WIDGET_EXTENSION_BUNDLE_ID=$chromium_bundle_id.ContentTodayExtension", "CHROMIUM_BUNDLE_ID=$output_name", "CHROMIUM_HANDOFF_ID=$chromium_handoff_id", "CHROMIUM_SHORT_NAME=$output_name",
diff --git a/ios/clean/chrome/test/perf/BUILD.gn b/ios/clean/chrome/test/perf/BUILD.gn index d984a55a..0eedbf2 100644 --- a/ios/clean/chrome/test/perf/BUILD.gn +++ b/ios/clean/chrome/test/perf/BUILD.gn
@@ -58,6 +58,7 @@ _eg_main_application_delegate = "MainApplicationDelegate" extra_substitutions = [ + "CONTENT_WIDGET_EXTENSION_BUNDLE_ID=$chromium_bundle_id.ContentTodayExtension", "CHROMIUM_HANDOFF_ID=$chromium_handoff_id", "CHROMIUM_SHORT_NAME=$target_name", "CHROMIUM_URL_SCHEME_1=$url_unsecure_scheme",
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc index 91dfe6d..6b5d0f108 100644 --- a/net/url_request/url_request.cc +++ b/net/url_request/url_request.cc
@@ -958,11 +958,10 @@ // not set to "null", a POST request from origin A to a malicious origin M // could be redirected by M back to A. // - // This behavior is specified in step 1 of step 10 of the 301, 302, 303, 307, - // 308 block of step 5 of Section 4.2 of Fetch[1] (which supercedes the - // behavior outlined in RFC 6454[2]. + // This behavior is specified in step 10 of the HTTP-redirect fetch + // algorithm[1] (which supercedes the behavior outlined in RFC 6454[2]. // - // [1]: https://fetch.spec.whatwg.org/#concept-http-fetch + // [1]: https://fetch.spec.whatwg.org/#http-redirect-fetch // [2]: https://tools.ietf.org/html/rfc6454#section-7 // // TODO(jww): This is a layering violation and should be refactored somewhere
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc index ac5a8c27..ae21dcd 100644 --- a/pdf/pdfium/pdfium_engine.cc +++ b/pdf/pdfium/pdfium_engine.cc
@@ -1772,6 +1772,7 @@ pp::Point point = event.GetPosition(); PDFiumPage::Area area = GetCharIndex(point, &page_index, &char_index, &form_type, &target); + DCHECK_GE(form_type, FPDF_FORMFIELD_UNKNOWN); mouse_down_state_.Set(area, target); // Decide whether to open link or not based on user action in mouse up and @@ -1791,10 +1792,8 @@ FPDF_PAGE page = pages_[page_index]->GetPage(); FORM_OnLButtonDown(form_, page, 0, page_x, page_y); - if (form_type > FPDF_FORMFIELD_UNKNOWN) { // returns -1 sometimes... + if (form_type != FPDF_FORMFIELD_UNKNOWN) { DCHECK_EQ(area, PDFiumPage::FormTypeToArea(form_type)); - mouse_down_state_.Set(area, target); - // Destroy SelectionChangeInvalidator object before SetInFormTextArea() // changes plugin's focus to be in form text area. This way, regular text // selection can be cleared when a user clicks into a form text area
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.cc b/services/ui/ws/server_window_compositor_frame_sink_manager.cc index aa5a769..e8fb206 100644 --- a/services/ui/ws/server_window_compositor_frame_sink_manager.cc +++ b/services/ui/ws/server_window_compositor_frame_sink_manager.cc
@@ -7,12 +7,12 @@ #include <utility> #include "base/command_line.h" -#include "cc/base/switches.h" #include "components/viz/common/display/renderer_settings.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/ui/ws/ids.h" #include "services/ui/ws/server_window.h" #include "services/ui/ws/server_window_delegate.h" +#include "ui/base/ui_base_switches.h" namespace ui { namespace ws { @@ -37,7 +37,7 @@ viz::RendererSettings settings; settings.show_overdraw_feedback = base::CommandLine::ForCurrentProcess()->HasSwitch( - cc::switches::kShowOverdrawFeedback); + switches::kShowOverdrawFeedback); // TODO(fsamuel): AcceleratedWidget cannot be transported over IPC for Mac // or Android. We should instead use GpuSurfaceTracker here on those
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json index 2767fe5..2315989 100644 --- a/testing/buildbot/chromium.perf.json +++ b/testing/buildbot/chromium.perf.json
@@ -2644,6 +2644,67 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-chromium" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build13-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=reference", + "--output-trace-tag=_ref" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases.reference", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build13-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": true, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -3275,7 +3336,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -3306,7 +3367,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -3702,7 +3763,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -3733,7 +3794,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -7661,6 +7722,67 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-chromium" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build73-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=reference", + "--output-trace-tag=_ref" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases.reference", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build73-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": true, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -8292,7 +8414,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -8323,7 +8445,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -8719,7 +8841,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -8750,7 +8872,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -11428,6 +11550,37 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-webview", + "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk" + ], + "isolate_name": "telemetry_perf_webview_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_webview_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build165-b1--device3", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -11760,7 +11913,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -11977,7 +12130,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -15306,6 +15459,67 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-chromium" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build15-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=reference", + "--output-trace-tag=_ref" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases.reference", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build15-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": true, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -15937,7 +16151,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -15968,7 +16182,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -16364,7 +16578,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -16395,7 +16609,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -19104,6 +19318,37 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-webview", + "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk" + ], + "isolate_name": "telemetry_perf_webview_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_webview_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build113-b1--device3", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -19436,7 +19681,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -19653,7 +19898,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -22982,6 +23227,67 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-chromium" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build9-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=reference", + "--output-trace-tag=_ref" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases.reference", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build9-b1--device7", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": true, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -23613,7 +23919,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -23644,7 +23950,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -24040,7 +24346,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -24071,7 +24377,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -27877,6 +28183,67 @@ }, { "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=android-chromium" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build47-b1--device4", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": false, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ + "smoothness.gpu_rasterization_and_decoding.image_decoding_cases", + "-v", + "--upload-results", + "--output-format=chartjson", + "--browser=reference", + "--output-trace-tag=_ref" + ], + "isolate_name": "telemetry_perf_tests", + "name": "smoothness.gpu_rasterization_and_decoding.image_decoding_cases.reference", + "override_compile_targets": [ + "telemetry_perf_tests" + ], + "swarming": { + "can_use_on_swarming_builders": true, + "dimension_sets": [ + { + "android_devices": "1", + "id": "build47-b1--device4", + "os": "Android", + "pool": "Chrome-perf" + } + ], + "expiration": 72000, + "hard_timeout": 10800, + "ignore_task_failure": true, + "io_timeout": 3600, + "upload_test_results": false + } + }, + { + "args": [ "smoothness.key_desktop_move_cases", "-v", "--upload-results", @@ -28508,7 +28875,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -28539,7 +28906,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600, @@ -28935,7 +29302,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": false, "io_timeout": 3600, @@ -28966,7 +29333,7 @@ "pool": "Chrome-perf" } ], - "expiration": 36000, + "expiration": 72000, "hard_timeout": 10800, "ignore_task_failure": true, "io_timeout": 3600,
diff --git a/testing/buildbot/filters/fuchsia.base_unittests.filter b/testing/buildbot/filters/fuchsia.base_unittests.filter index efbfe79..1a43507 100644 --- a/testing/buildbot/filters/fuchsia.base_unittests.filter +++ b/testing/buildbot/filters/fuchsia.base_unittests.filter
@@ -18,7 +18,6 @@ -FileProxyTest.SetTimes -FileUtilProxyTest.Touch -FileUtilTest.FileToFILE --LoggingTest.CheckCausesDistinctBreakpoints -NativeLibraryTest.LoadLibrary -NativeLibraryTest.LoadLibraryPreferOwnSymbols -PathServiceTest.Get
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptController.h b/third_party/WebKit/Source/bindings/core/v8/ScriptController.h index 5eba8bda..5a2d403 100644 --- a/third_party/WebKit/Source/bindings/core/v8/ScriptController.h +++ b/third_party/WebKit/Source/bindings/core/v8/ScriptController.h
@@ -37,7 +37,6 @@ #include "platform/bindings/SharedPersistent.h" #include "platform/heap/Handle.h" #include "platform/loader/fetch/AccessControlStatus.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/wtf/HashMap.h" #include "platform/wtf/Noncopyable.h" #include "platform/wtf/Vector.h"
diff --git a/third_party/WebKit/Source/core/css/BUILD.gn b/third_party/WebKit/Source/core/css/BUILD.gn index 9951d500..5d886d9 100644 --- a/third_party/WebKit/Source/core/css/BUILD.gn +++ b/third_party/WebKit/Source/core/css/BUILD.gn
@@ -188,6 +188,8 @@ "FontFaceCache.h", "FontFaceSet.cpp", "FontFaceSet.h", + "FontFaceSetDocument.cpp", + "FontFaceSetDocument.h", "FontFaceSetLoadEvent.cpp", "FontFaceSetLoadEvent.h", "FontFaceSource.cpp",
diff --git a/third_party/WebKit/Source/core/css/CSSFontFace.cpp b/third_party/WebKit/Source/core/css/CSSFontFace.cpp index f250769..aef7708 100644 --- a/third_party/WebKit/Source/core/css/CSSFontFace.cpp +++ b/third_party/WebKit/Source/core/css/CSSFontFace.cpp
@@ -25,15 +25,15 @@ #include "core/css/CSSFontFace.h" +#include <algorithm> #include "core/css/CSSFontFaceSource.h" #include "core/css/CSSFontSelector.h" #include "core/css/CSSSegmentedFontFace.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/css/RemoteFontFaceSource.h" #include "core/frame/UseCounter.h" #include "platform/fonts/FontDescription.h" #include "platform/fonts/SimpleFontData.h" -#include <algorithm> namespace blink { @@ -187,7 +187,7 @@ return; Document* document = ToDocument(font_face_->GetExecutionContext()); if (document && new_status == FontFace::kLoading) - FontFaceSet::From(*document)->BeginFontLoading(font_face_); + FontFaceSetDocument::From(*document)->BeginFontLoading(font_face_); } DEFINE_TRACE(CSSFontFace) {
diff --git a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp index 5acadcd..ae5ac87a 100644 --- a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp +++ b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
@@ -29,7 +29,7 @@ #include "build/build_config.h" #include "core/css/CSSSegmentedFontFace.h" #include "core/css/CSSValueList.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/css/resolver/StyleResolver.h" #include "core/dom/Document.h" #include "core/frame/LocalFrame.h" @@ -54,7 +54,8 @@ DCHECK(document_); DCHECK(document_->GetFrame()); FontCache::GetFontCache()->AddClient(this); - FontFaceSet::From(*document)->AddFontFacesToFontFaceCache(&font_face_cache_); + FontFaceSetDocument::From(*document)->AddFontFacesToFontFaceCache( + &font_face_cache_); } CSSFontSelector::~CSSFontSelector() {}
diff --git a/third_party/WebKit/Source/core/css/FontFaceSet.cpp b/third_party/WebKit/Source/core/css/FontFaceSet.cpp index 47b9f0e..2246f61 100644 --- a/third_party/WebKit/Source/core/css/FontFaceSet.cpp +++ b/third_party/WebKit/Source/core/css/FontFaceSet.cpp
@@ -1,582 +1,11 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #include "core/css/FontFaceSet.h" -#include "bindings/core/v8/Dictionary.h" -#include "bindings/core/v8/ScriptPromiseResolver.h" -#include "core/css/CSSFontSelector.h" -#include "core/css/CSSSegmentedFontFace.h" -#include "core/css/FontFaceCache.h" -#include "core/css/FontFaceSetLoadEvent.h" -#include "core/css/StylePropertySet.h" -#include "core/css/parser/CSSParser.h" -#include "core/css/resolver/StyleResolver.h" -#include "core/dom/Document.h" -#include "core/dom/StyleEngine.h" -#include "core/frame/LocalFrame.h" -#include "core/frame/LocalFrameView.h" -#include "core/style/ComputedStyle.h" -#include "platform/Histogram.h" -#include "platform/bindings/ScriptState.h" - namespace blink { -static const int kDefaultFontSize = 10; -static const char kDefaultFontFamily[] = "sans-serif"; - -class LoadFontPromiseResolver final - : public GarbageCollectedFinalized<LoadFontPromiseResolver>, - public FontFace::LoadFontCallback { - USING_GARBAGE_COLLECTED_MIXIN(LoadFontPromiseResolver); - - public: - static LoadFontPromiseResolver* Create(FontFaceArray faces, - ScriptState* script_state) { - return new LoadFontPromiseResolver(faces, script_state); - } - - void LoadFonts(); - ScriptPromise Promise() { return resolver_->Promise(); } - - void NotifyLoaded(FontFace*) override; - void NotifyError(FontFace*) override; - - DECLARE_VIRTUAL_TRACE(); - - private: - LoadFontPromiseResolver(FontFaceArray faces, ScriptState* script_state) - : num_loading_(faces.size()), - error_occured_(false), - resolver_(ScriptPromiseResolver::Create(script_state)) { - font_faces_.swap(faces); - } - - HeapVector<Member<FontFace>> font_faces_; - int num_loading_; - bool error_occured_; - Member<ScriptPromiseResolver> resolver_; -}; - -void LoadFontPromiseResolver::LoadFonts() { - if (!num_loading_) { - resolver_->Resolve(font_faces_); - return; - } - - for (size_t i = 0; i < font_faces_.size(); i++) - font_faces_[i]->LoadWithCallback(this); -} - -void LoadFontPromiseResolver::NotifyLoaded(FontFace* font_face) { - num_loading_--; - if (num_loading_ || error_occured_) - return; - - resolver_->Resolve(font_faces_); -} - -void LoadFontPromiseResolver::NotifyError(FontFace* font_face) { - num_loading_--; - if (!error_occured_) { - error_occured_ = true; - resolver_->Reject(font_face->GetError()); - } -} - -DEFINE_TRACE(LoadFontPromiseResolver) { - visitor->Trace(font_faces_); - visitor->Trace(resolver_); - LoadFontCallback::Trace(visitor); -} - -FontFaceSet::FontFaceSet(Document& document) - : Supplement<Document>(document), - SuspendableObject(&document), - should_fire_loading_event_(false), - is_loading_(false), - ready_(new ReadyProperty(GetExecutionContext(), - this, - ReadyProperty::kReady)), - async_runner_(AsyncMethodRunner<FontFaceSet>::Create( - this, - &FontFaceSet::HandlePendingEventsAndPromises)) { - SuspendIfNeeded(); -} - -FontFaceSet::~FontFaceSet() {} - -Document* FontFaceSet::GetDocument() const { - return ToDocument(GetExecutionContext()); -} - -bool FontFaceSet::InActiveDocumentContext() const { - ExecutionContext* context = GetExecutionContext(); - return context && ToDocument(context)->IsActive(); -} - -void FontFaceSet::AddFontFacesToFontFaceCache(FontFaceCache* font_face_cache) { - for (const auto& font_face : non_css_connected_faces_) - font_face_cache->AddFontFace(font_face, false); -} - -const AtomicString& FontFaceSet::InterfaceName() const { - return EventTargetNames::FontFaceSet; -} - -ExecutionContext* FontFaceSet::GetExecutionContext() const { - return SuspendableObject::GetExecutionContext(); -} - -AtomicString FontFaceSet::status() const { - DEFINE_STATIC_LOCAL(AtomicString, loading, ("loading")); - DEFINE_STATIC_LOCAL(AtomicString, loaded, ("loaded")); - return is_loading_ ? loading : loaded; -} - -void FontFaceSet::HandlePendingEventsAndPromisesSoon() { - // async_runner_ will be automatically stopped on destruction. - async_runner_->RunAsync(); -} - -void FontFaceSet::DidLayout() { - if (GetDocument()->GetFrame()->IsMainFrame() && loading_fonts_.IsEmpty()) - histogram_.Record(); - if (!ShouldSignalReady()) - return; - HandlePendingEventsAndPromisesSoon(); -} - -bool FontFaceSet::ShouldSignalReady() const { - if (!loading_fonts_.IsEmpty()) - return false; - return is_loading_ || ready_->GetState() == ReadyProperty::kPending; -} - -void FontFaceSet::HandlePendingEventsAndPromises() { - FireLoadingEvent(); - FireDoneEventIfPossible(); -} - -void FontFaceSet::FireLoadingEvent() { - if (should_fire_loading_event_) { - should_fire_loading_event_ = false; - DispatchEvent( - FontFaceSetLoadEvent::CreateForFontFaces(EventTypeNames::loading)); - } -} - -void FontFaceSet::Suspend() { - async_runner_->Suspend(); -} - -void FontFaceSet::Resume() { - async_runner_->Resume(); -} - -void FontFaceSet::ContextDestroyed(ExecutionContext*) { - async_runner_->Stop(); -} - -void FontFaceSet::BeginFontLoading(FontFace* font_face) { - histogram_.IncrementCount(); - AddToLoadingFonts(font_face); -} - -void FontFaceSet::NotifyLoaded(FontFace* font_face) { - histogram_.UpdateStatus(font_face); - loaded_fonts_.push_back(font_face); - RemoveFromLoadingFonts(font_face); -} - -void FontFaceSet::NotifyError(FontFace* font_face) { - histogram_.UpdateStatus(font_face); - failed_fonts_.push_back(font_face); - RemoveFromLoadingFonts(font_face); -} - -size_t FontFaceSet::ApproximateBlankCharacterCount() const { - size_t count = 0; - for (auto& font_face : loading_fonts_) - count += font_face->ApproximateBlankCharacterCount(); - return count; -} - -void FontFaceSet::AddToLoadingFonts(FontFace* font_face) { - if (!is_loading_) { - is_loading_ = true; - should_fire_loading_event_ = true; - if (ready_->GetState() != ReadyProperty::kPending) - ready_->Reset(); - HandlePendingEventsAndPromisesSoon(); - } - loading_fonts_.insert(font_face); - font_face->AddCallback(this); -} - -void FontFaceSet::RemoveFromLoadingFonts(FontFace* font_face) { - loading_fonts_.erase(font_face); - if (loading_fonts_.IsEmpty()) - HandlePendingEventsAndPromisesSoon(); -} - -ScriptPromise FontFaceSet::ready(ScriptState* script_state) { - if (ready_->GetState() != ReadyProperty::kPending && - InActiveDocumentContext()) { - // |ready_| is already resolved, but there may be pending stylesheet - // changes and/or layout operations that may cause another font loads. - // So synchronously update style and layout here. - // This may trigger font loads, and replace |ready_| with a new Promise. - GetDocument()->UpdateStyleAndLayout(); - } - return ready_->Promise(script_state->World()); -} - -FontFaceSet* FontFaceSet::addForBinding(ScriptState*, - FontFace* font_face, - ExceptionState&) { - DCHECK(font_face); - if (!InActiveDocumentContext()) - return this; - if (non_css_connected_faces_.Contains(font_face)) - return this; - if (IsCSSConnectedFontFace(font_face)) - return this; - CSSFontSelector* font_selector = - GetDocument()->GetStyleEngine().GetFontSelector(); - non_css_connected_faces_.insert(font_face); - font_selector->GetFontFaceCache()->AddFontFace(font_face, false); - if (font_face->LoadStatus() == FontFace::kLoading) - AddToLoadingFonts(font_face); - font_selector->FontFaceInvalidated(); - return this; -} - -void FontFaceSet::clearForBinding(ScriptState*, ExceptionState&) { - if (!InActiveDocumentContext() || non_css_connected_faces_.IsEmpty()) - return; - CSSFontSelector* font_selector = - GetDocument()->GetStyleEngine().GetFontSelector(); - FontFaceCache* font_face_cache = font_selector->GetFontFaceCache(); - for (const auto& font_face : non_css_connected_faces_) { - font_face_cache->RemoveFontFace(font_face.Get(), false); - if (font_face->LoadStatus() == FontFace::kLoading) - RemoveFromLoadingFonts(font_face); - } - non_css_connected_faces_.clear(); - font_selector->FontFaceInvalidated(); -} - -bool FontFaceSet::deleteForBinding(ScriptState*, - FontFace* font_face, - ExceptionState&) { - DCHECK(font_face); - if (!InActiveDocumentContext()) - return false; - HeapListHashSet<Member<FontFace>>::iterator it = - non_css_connected_faces_.find(font_face); - if (it != non_css_connected_faces_.end()) { - non_css_connected_faces_.erase(it); - CSSFontSelector* font_selector = - GetDocument()->GetStyleEngine().GetFontSelector(); - font_selector->GetFontFaceCache()->RemoveFontFace(font_face, false); - if (font_face->LoadStatus() == FontFace::kLoading) - RemoveFromLoadingFonts(font_face); - font_selector->FontFaceInvalidated(); - return true; - } - return false; -} - -bool FontFaceSet::hasForBinding(ScriptState*, - FontFace* font_face, - ExceptionState&) const { - DCHECK(font_face); - if (!InActiveDocumentContext()) - return false; - return non_css_connected_faces_.Contains(font_face) || - IsCSSConnectedFontFace(font_face); -} - -const HeapListHashSet<Member<FontFace>>& FontFaceSet::CssConnectedFontFaceList() - const { - Document* document = this->GetDocument(); - document->UpdateActiveStyle(); - return document->GetStyleEngine() - .GetFontSelector() - ->GetFontFaceCache() - ->CssConnectedFontFaces(); -} - -bool FontFaceSet::IsCSSConnectedFontFace(FontFace* font_face) const { - return CssConnectedFontFaceList().Contains(font_face); -} - -size_t FontFaceSet::size() const { - if (!InActiveDocumentContext()) - return non_css_connected_faces_.size(); - return CssConnectedFontFaceList().size() + non_css_connected_faces_.size(); -} - -void FontFaceSet::FireDoneEventIfPossible() { - if (should_fire_loading_event_) - return; - if (!ShouldSignalReady()) - return; - Document* d = GetDocument(); - if (!d) - return; - - // If the layout was invalidated in between when we thought layout - // was updated and when we're ready to fire the event, just wait - // until after the next layout before firing events. - if (!d->View() || d->View()->NeedsLayout()) - return; - - if (is_loading_) { - FontFaceSetLoadEvent* done_event = nullptr; - FontFaceSetLoadEvent* error_event = nullptr; - done_event = FontFaceSetLoadEvent::CreateForFontFaces( - EventTypeNames::loadingdone, loaded_fonts_); - loaded_fonts_.clear(); - if (!failed_fonts_.IsEmpty()) { - error_event = FontFaceSetLoadEvent::CreateForFontFaces( - EventTypeNames::loadingerror, failed_fonts_); - failed_fonts_.clear(); - } - is_loading_ = false; - DispatchEvent(done_event); - if (error_event) - DispatchEvent(error_event); - } - - if (ready_->GetState() == ReadyProperty::kPending) - ready_->Resolve(this); -} - -ScriptPromise FontFaceSet::load(ScriptState* script_state, - const String& font_string, - const String& text) { - if (!InActiveDocumentContext()) - return ScriptPromise(); - - Font font; - if (!ResolveFontStyle(font_string, font)) { - ScriptPromiseResolver* resolver = - ScriptPromiseResolver::Create(script_state); - ScriptPromise promise = resolver->Promise(); - resolver->Reject(DOMException::Create( - kSyntaxError, "Could not resolve '" + font_string + "' as a font.")); - return promise; - } - - FontFaceCache* font_face_cache = - GetDocument()->GetStyleEngine().GetFontSelector()->GetFontFaceCache(); - FontFaceArray faces; - for (const FontFamily* f = &font.GetFontDescription().Family(); f; - f = f->Next()) { - CSSSegmentedFontFace* segmented_font_face = - font_face_cache->Get(font.GetFontDescription(), f->Family()); - if (segmented_font_face) - segmented_font_face->Match(text, faces); - } - - LoadFontPromiseResolver* resolver = - LoadFontPromiseResolver::Create(faces, script_state); - ScriptPromise promise = resolver->Promise(); - // After this, resolver->promise() may return null. - resolver->LoadFonts(); - return promise; -} - -bool FontFaceSet::check(const String& font_string, - const String& text, - ExceptionState& exception_state) { - if (!InActiveDocumentContext()) - return false; - - Font font; - if (!ResolveFontStyle(font_string, font)) { - exception_state.ThrowDOMException( - kSyntaxError, "Could not resolve '" + font_string + "' as a font."); - return false; - } - - CSSFontSelector* font_selector = - GetDocument()->GetStyleEngine().GetFontSelector(); - FontFaceCache* font_face_cache = font_selector->GetFontFaceCache(); - - bool has_loaded_faces = false; - for (const FontFamily* f = &font.GetFontDescription().Family(); f; - f = f->Next()) { - CSSSegmentedFontFace* face = - font_face_cache->Get(font.GetFontDescription(), f->Family()); - if (face) { - if (!face->CheckFont(text)) - return false; - has_loaded_faces = true; - } - } - if (has_loaded_faces) - return true; - for (const FontFamily* f = &font.GetFontDescription().Family(); f; - f = f->Next()) { - if (font_selector->IsPlatformFamilyMatchAvailable(font.GetFontDescription(), - f->Family())) - return true; - } - return false; -} - -bool FontFaceSet::ResolveFontStyle(const String& font_string, Font& font) { - if (font_string.IsEmpty()) - return false; - - // Interpret fontString in the same way as the 'font' attribute of - // CanvasRenderingContext2D. - MutableStylePropertySet* parsed_style = - MutableStylePropertySet::Create(kHTMLStandardMode); - CSSParser::ParseValue(parsed_style, CSSPropertyFont, font_string, true); - if (parsed_style->IsEmpty()) - return false; - - String font_value = parsed_style->GetPropertyValue(CSSPropertyFont); - if (font_value == "inherit" || font_value == "initial") - return false; - - RefPtr<ComputedStyle> style = ComputedStyle::Create(); - - FontFamily font_family; - font_family.SetFamily(kDefaultFontFamily); - - FontDescription default_font_description; - default_font_description.SetFamily(font_family); - default_font_description.SetSpecifiedSize(kDefaultFontSize); - default_font_description.SetComputedSize(kDefaultFontSize); - - style->SetFontDescription(default_font_description); - - style->GetFont().Update(style->GetFont().GetFontSelector()); - - GetDocument()->UpdateActiveStyle(); - GetDocument()->EnsureStyleResolver().ComputeFont(style.Get(), *parsed_style); - - font = style->GetFont(); - font.Update(GetDocument()->GetStyleEngine().GetFontSelector()); - return true; -} - -void FontFaceSet::FontLoadHistogram::UpdateStatus(FontFace* font_face) { - if (status_ == kReported) - return; - if (font_face->HadBlankText()) - status_ = kHadBlankText; - else if (status_ == kNoWebFonts) - status_ = kDidNotHaveBlankText; -} - -void FontFaceSet::FontLoadHistogram::Record() { - if (!recorded_) { - recorded_ = true; - DEFINE_STATIC_LOCAL(CustomCountHistogram, web_fonts_in_page_histogram, - ("WebFont.WebFontsInPage", 1, 100, 50)); - web_fonts_in_page_histogram.Count(count_); - } - if (status_ == kHadBlankText || status_ == kDidNotHaveBlankText) { - DEFINE_STATIC_LOCAL(EnumerationHistogram, had_blank_text_histogram, - ("WebFont.HadBlankText", 2)); - had_blank_text_histogram.Count(status_ == kHadBlankText ? 1 : 0); - status_ = kReported; - } -} - -FontFaceSet* FontFaceSet::From(Document& document) { - FontFaceSet* fonts = static_cast<FontFaceSet*>( - Supplement<Document>::From(document, SupplementName())); - if (!fonts) { - fonts = FontFaceSet::Create(document); - Supplement<Document>::ProvideTo(document, SupplementName(), fonts); - } - - return fonts; -} - -void FontFaceSet::DidLayout(Document& document) { - if (FontFaceSet* fonts = static_cast<FontFaceSet*>( - Supplement<Document>::From(document, SupplementName()))) - fonts->DidLayout(); -} - -size_t FontFaceSet::ApproximateBlankCharacterCount(Document& document) { - if (FontFaceSet* fonts = static_cast<FontFaceSet*>( - Supplement<Document>::From(document, SupplementName()))) - return fonts->ApproximateBlankCharacterCount(); - return 0; -} - -FontFaceSetIterable::IterationSource* FontFaceSet::StartIteration( - ScriptState*, - ExceptionState&) { - // Setlike should iterate each item in insertion order, and items should - // be keep on up to date. But since blink does not have a way to hook up CSS - // modification, take a snapshot here, and make it ordered as follows. - HeapVector<Member<FontFace>> font_faces; - if (InActiveDocumentContext()) { - const HeapListHashSet<Member<FontFace>>& css_connected_faces = - CssConnectedFontFaceList(); - font_faces.ReserveInitialCapacity(css_connected_faces.size() + - non_css_connected_faces_.size()); - for (const auto& font_face : css_connected_faces) - font_faces.push_back(font_face); - for (const auto& font_face : non_css_connected_faces_) - font_faces.push_back(font_face); - } - return new IterationSource(font_faces); -} - -bool FontFaceSet::IterationSource::Next(ScriptState*, - Member<FontFace>& key, - Member<FontFace>& value, - ExceptionState&) { - if (font_faces_.size() <= index_) - return false; - key = value = font_faces_[index_++]; - return true; -} -DEFINE_TRACE(FontFaceSet) { - visitor->Trace(ready_); - visitor->Trace(loading_fonts_); - visitor->Trace(loaded_fonts_); - visitor->Trace(failed_fonts_); - visitor->Trace(non_css_connected_faces_); - visitor->Trace(async_runner_); - EventTargetWithInlineData::Trace(visitor); - Supplement<Document>::Trace(visitor); - SuspendableObject::Trace(visitor); - FontFace::LoadFontCallback::Trace(visitor); -} } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/FontFaceSet.h b/third_party/WebKit/Source/core/css/FontFaceSet.h index 1114920..a9275645 100644 --- a/third_party/WebKit/Source/core/css/FontFaceSet.h +++ b/third_party/WebKit/Source/core/css/FontFaceSet.h
@@ -1,27 +1,6 @@ -/* - * Copyright (C) 2013 Google Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #ifndef FontFaceSet_h #define FontFaceSet_h @@ -29,14 +8,9 @@ #include "bindings/core/v8/Iterable.h" #include "bindings/core/v8/ScriptPromise.h" #include "core/css/FontFace.h" -#include "core/dom/Document.h" -#include "core/dom/SuspendableObject.h" #include "core/events/EventListener.h" #include "core/events/EventTarget.h" -#include "platform/AsyncMethodRunner.h" -#include "platform/heap/Handle.h" -#include "platform/wtf/Allocator.h" -#include "platform/wtf/Vector.h" +#include "platform/bindings/ScriptWrappable.h" // Mac OS X 10.6 SDK defines check() macro that interferes with our check() // method @@ -46,79 +20,53 @@ namespace blink { -class ExceptionState; -class Font; -class FontFaceCache; -class ExecutionContext; - using FontFaceSetIterable = SetlikeIterable<Member<FontFace>>; -class CORE_EXPORT FontFaceSet final : public EventTargetWithInlineData, - public Supplement<Document>, - public SuspendableObject, - public FontFaceSetIterable, - public FontFace::LoadFontCallback { - USING_GARBAGE_COLLECTED_MIXIN(FontFaceSet); +class CORE_EXPORT FontFaceSet : public EventTargetWithInlineData, + public FontFaceSetIterable { DEFINE_WRAPPERTYPEINFO(); WTF_MAKE_NONCOPYABLE(FontFaceSet); public: - ~FontFaceSet() override; + FontFaceSet() {} + ~FontFaceSet() {} DEFINE_ATTRIBUTE_EVENT_LISTENER(loading); DEFINE_ATTRIBUTE_EVENT_LISTENER(loadingdone); DEFINE_ATTRIBUTE_EVENT_LISTENER(loadingerror); - bool check(const String& font, const String& text, ExceptionState&); - ScriptPromise load(ScriptState*, const String& font, const String& text); - ScriptPromise ready(ScriptState*); + virtual bool check(const String& font, + const String& text, + ExceptionState&) = 0; + virtual ScriptPromise load(ScriptState*, + const String& font, + const String& text) = 0; + virtual ScriptPromise ready(ScriptState*) = 0; - FontFaceSet* addForBinding(ScriptState*, FontFace*, ExceptionState&); - void clearForBinding(ScriptState*, ExceptionState&); - bool deleteForBinding(ScriptState*, FontFace*, ExceptionState&); - bool hasForBinding(ScriptState*, FontFace*, ExceptionState&) const; - - size_t size() const; - AtomicString status() const; - - ExecutionContext* GetExecutionContext() const override; - const AtomicString& InterfaceName() const override; - - Document* GetDocument() const; - - void DidLayout(); - void BeginFontLoading(FontFace*); - - // FontFace::LoadFontCallback - void NotifyLoaded(FontFace*) override; - void NotifyError(FontFace*) override; - - size_t ApproximateBlankCharacterCount() const; - - // SuspendableObject - void Suspend() override; - void Resume() override; - void ContextDestroyed(ExecutionContext*) override; - - static FontFaceSet* From(Document&); - static void DidLayout(Document&); - static size_t ApproximateBlankCharacterCount(Document&); - - static const char* SupplementName() { return "FontFaceSet"; } - - void AddFontFacesToFontFaceCache(FontFaceCache*); - - DECLARE_VIRTUAL_TRACE(); - - private: - static FontFaceSet* Create(Document& document) { - return new FontFaceSet(document); + virtual ExecutionContext* GetExecutionContext() const = 0; + const AtomicString& InterfaceName() const { + return EventTargetNames::FontFaceSet; } + virtual FontFaceSet* addForBinding(ScriptState*, + FontFace*, + ExceptionState&) = 0; + virtual void clearForBinding(ScriptState*, ExceptionState&) = 0; + virtual bool deleteForBinding(ScriptState*, FontFace*, ExceptionState&) = 0; + virtual bool hasForBinding(ScriptState*, + FontFace*, + ExceptionState&) const = 0; + + virtual size_t size() const = 0; + virtual AtomicString status() const = 0; + + DEFINE_INLINE_VIRTUAL_TRACE() {} + + protected: // Iterable overrides. - FontFaceSetIterable::IterationSource* StartIteration( + virtual FontFaceSetIterable::IterationSource* StartIteration( ScriptState*, - ExceptionState&) override; + ExceptionState&) = 0; class IterationSource final : public FontFaceSetIterable::IterationSource { public: @@ -138,52 +86,6 @@ size_t index_; HeapVector<Member<FontFace>> font_faces_; }; - - class FontLoadHistogram { - DISALLOW_NEW(); - - public: - enum Status { kNoWebFonts, kHadBlankText, kDidNotHaveBlankText, kReported }; - FontLoadHistogram() : status_(kNoWebFonts), count_(0), recorded_(false) {} - void IncrementCount() { count_++; } - void UpdateStatus(FontFace*); - void Record(); - - private: - Status status_; - int count_; - bool recorded_; - }; - - explicit FontFaceSet(Document&); - - bool InActiveDocumentContext() const; - void AddToLoadingFonts(FontFace*); - void RemoveFromLoadingFonts(FontFace*); - void FireLoadingEvent(); - void FireDoneEventIfPossible(); - bool ResolveFontStyle(const String&, Font&); - void HandlePendingEventsAndPromisesSoon(); - void HandlePendingEventsAndPromises(); - const HeapListHashSet<Member<FontFace>>& CssConnectedFontFaceList() const; - bool IsCSSConnectedFontFace(FontFace*) const; - bool ShouldSignalReady() const; - - using ReadyProperty = ScriptPromiseProperty<Member<FontFaceSet>, - Member<FontFaceSet>, - Member<DOMException>>; - - HeapHashSet<Member<FontFace>> loading_fonts_; - bool should_fire_loading_event_; - bool is_loading_; - Member<ReadyProperty> ready_; - FontFaceArray loaded_fonts_; - FontFaceArray failed_fonts_; - HeapListHashSet<Member<FontFace>> non_css_connected_faces_; - - Member<AsyncMethodRunner<FontFaceSet>> async_runner_; - - FontLoadHistogram histogram_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetDocument.cpp b/third_party/WebKit/Source/core/css/FontFaceSetDocument.cpp new file mode 100644 index 0000000..f480e0927 --- /dev/null +++ b/third_party/WebKit/Source/core/css/FontFaceSetDocument.cpp
@@ -0,0 +1,581 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#include "core/css/FontFaceSetDocument.h" + +#include "bindings/core/v8/Dictionary.h" +#include "bindings/core/v8/ScriptPromiseResolver.h" +#include "core/css/CSSFontSelector.h" +#include "core/css/CSSSegmentedFontFace.h" +#include "core/css/FontFaceCache.h" +#include "core/css/FontFaceSetLoadEvent.h" +#include "core/css/StylePropertySet.h" +#include "core/css/parser/CSSParser.h" +#include "core/css/resolver/StyleResolver.h" +#include "core/dom/Document.h" +#include "core/dom/StyleEngine.h" +#include "core/frame/LocalFrame.h" +#include "core/frame/LocalFrameView.h" +#include "core/style/ComputedStyle.h" +#include "platform/Histogram.h" +#include "platform/bindings/ScriptState.h" + +namespace blink { + +static const int kDefaultFontSize = 10; +static const char kDefaultFontFamily[] = "sans-serif"; + +class LoadFontPromiseResolver final + : public GarbageCollectedFinalized<LoadFontPromiseResolver>, + public FontFace::LoadFontCallback { + USING_GARBAGE_COLLECTED_MIXIN(LoadFontPromiseResolver); + + public: + static LoadFontPromiseResolver* Create(FontFaceArray faces, + ScriptState* script_state) { + return new LoadFontPromiseResolver(faces, script_state); + } + + void LoadFonts(); + ScriptPromise Promise() { return resolver_->Promise(); } + + void NotifyLoaded(FontFace*) override; + void NotifyError(FontFace*) override; + + DECLARE_VIRTUAL_TRACE(); + + private: + LoadFontPromiseResolver(FontFaceArray faces, ScriptState* script_state) + : num_loading_(faces.size()), + error_occured_(false), + resolver_(ScriptPromiseResolver::Create(script_state)) { + font_faces_.swap(faces); + } + + HeapVector<Member<FontFace>> font_faces_; + int num_loading_; + bool error_occured_; + Member<ScriptPromiseResolver> resolver_; +}; + +void LoadFontPromiseResolver::LoadFonts() { + if (!num_loading_) { + resolver_->Resolve(font_faces_); + return; + } + + for (size_t i = 0; i < font_faces_.size(); i++) + font_faces_[i]->LoadWithCallback(this); +} + +void LoadFontPromiseResolver::NotifyLoaded(FontFace* font_face) { + num_loading_--; + if (num_loading_ || error_occured_) + return; + + resolver_->Resolve(font_faces_); +} + +void LoadFontPromiseResolver::NotifyError(FontFace* font_face) { + num_loading_--; + if (!error_occured_) { + error_occured_ = true; + resolver_->Reject(font_face->GetError()); + } +} + +DEFINE_TRACE(LoadFontPromiseResolver) { + visitor->Trace(font_faces_); + visitor->Trace(resolver_); + LoadFontCallback::Trace(visitor); +} + +FontFaceSetDocument::FontFaceSetDocument(Document& document) + : Supplement<Document>(document), + SuspendableObject(&document), + should_fire_loading_event_(false), + is_loading_(false), + ready_(new ReadyProperty(GetExecutionContext(), + this, + ReadyProperty::kReady)), + async_runner_(AsyncMethodRunner<FontFaceSetDocument>::Create( + this, + &FontFaceSetDocument::HandlePendingEventsAndPromises)) { + SuspendIfNeeded(); +} + +FontFaceSetDocument::~FontFaceSetDocument() {} + +Document* FontFaceSetDocument::GetDocument() const { + return ToDocument(GetExecutionContext()); +} + +bool FontFaceSetDocument::InActiveDocumentContext() const { + ExecutionContext* context = GetExecutionContext(); + return context && ToDocument(context)->IsActive(); +} + +void FontFaceSetDocument::AddFontFacesToFontFaceCache( + FontFaceCache* font_face_cache) { + for (const auto& font_face : non_css_connected_faces_) + font_face_cache->AddFontFace(font_face, false); +} + +ExecutionContext* FontFaceSetDocument::GetExecutionContext() const { + return SuspendableObject::GetExecutionContext(); +} + +AtomicString FontFaceSetDocument::status() const { + DEFINE_STATIC_LOCAL(AtomicString, loading, ("loading")); + DEFINE_STATIC_LOCAL(AtomicString, loaded, ("loaded")); + return is_loading_ ? loading : loaded; +} + +void FontFaceSetDocument::HandlePendingEventsAndPromisesSoon() { + // async_runner_ will be automatically stopped on destruction. + async_runner_->RunAsync(); +} + +void FontFaceSetDocument::DidLayout() { + if (GetDocument()->GetFrame()->IsMainFrame() && loading_fonts_.IsEmpty()) + histogram_.Record(); + if (!ShouldSignalReady()) + return; + HandlePendingEventsAndPromisesSoon(); +} + +bool FontFaceSetDocument::ShouldSignalReady() const { + if (!loading_fonts_.IsEmpty()) + return false; + return is_loading_ || ready_->GetState() == ReadyProperty::kPending; +} + +void FontFaceSetDocument::HandlePendingEventsAndPromises() { + FireLoadingEvent(); + FireDoneEventIfPossible(); +} + +void FontFaceSetDocument::FireLoadingEvent() { + if (should_fire_loading_event_) { + should_fire_loading_event_ = false; + DispatchEvent( + FontFaceSetLoadEvent::CreateForFontFaces(EventTypeNames::loading)); + } +} + +void FontFaceSetDocument::Suspend() { + async_runner_->Suspend(); +} + +void FontFaceSetDocument::Resume() { + async_runner_->Resume(); +} + +void FontFaceSetDocument::ContextDestroyed(ExecutionContext*) { + async_runner_->Stop(); +} + +void FontFaceSetDocument::BeginFontLoading(FontFace* font_face) { + histogram_.IncrementCount(); + AddToLoadingFonts(font_face); +} + +void FontFaceSetDocument::NotifyLoaded(FontFace* font_face) { + histogram_.UpdateStatus(font_face); + loaded_fonts_.push_back(font_face); + RemoveFromLoadingFonts(font_face); +} + +void FontFaceSetDocument::NotifyError(FontFace* font_face) { + histogram_.UpdateStatus(font_face); + failed_fonts_.push_back(font_face); + RemoveFromLoadingFonts(font_face); +} + +size_t FontFaceSetDocument::ApproximateBlankCharacterCount() const { + size_t count = 0; + for (auto& font_face : loading_fonts_) + count += font_face->ApproximateBlankCharacterCount(); + return count; +} + +void FontFaceSetDocument::AddToLoadingFonts(FontFace* font_face) { + if (!is_loading_) { + is_loading_ = true; + should_fire_loading_event_ = true; + if (ready_->GetState() != ReadyProperty::kPending) + ready_->Reset(); + HandlePendingEventsAndPromisesSoon(); + } + loading_fonts_.insert(font_face); + font_face->AddCallback(this); +} + +void FontFaceSetDocument::RemoveFromLoadingFonts(FontFace* font_face) { + loading_fonts_.erase(font_face); + if (loading_fonts_.IsEmpty()) + HandlePendingEventsAndPromisesSoon(); +} + +ScriptPromise FontFaceSetDocument::ready(ScriptState* script_state) { + if (ready_->GetState() != ReadyProperty::kPending && + InActiveDocumentContext()) { + // |ready_| is already resolved, but there may be pending stylesheet + // changes and/or layout operations that may cause another font loads. + // So synchronously update style and layout here. + // This may trigger font loads, and replace |ready_| with a new Promise. + GetDocument()->UpdateStyleAndLayout(); + } + return ready_->Promise(script_state->World()); +} + +FontFaceSet* FontFaceSetDocument::addForBinding(ScriptState*, + FontFace* font_face, + ExceptionState&) { + DCHECK(font_face); + if (!InActiveDocumentContext()) + return this; + if (non_css_connected_faces_.Contains(font_face)) + return this; + if (IsCSSConnectedFontFace(font_face)) + return this; + CSSFontSelector* font_selector = + GetDocument()->GetStyleEngine().GetFontSelector(); + non_css_connected_faces_.insert(font_face); + font_selector->GetFontFaceCache()->AddFontFace(font_face, false); + if (font_face->LoadStatus() == FontFace::kLoading) + AddToLoadingFonts(font_face); + font_selector->FontFaceInvalidated(); + return this; +} + +void FontFaceSetDocument::clearForBinding(ScriptState*, ExceptionState&) { + if (!InActiveDocumentContext() || non_css_connected_faces_.IsEmpty()) + return; + CSSFontSelector* font_selector = + GetDocument()->GetStyleEngine().GetFontSelector(); + FontFaceCache* font_face_cache = font_selector->GetFontFaceCache(); + for (const auto& font_face : non_css_connected_faces_) { + font_face_cache->RemoveFontFace(font_face.Get(), false); + if (font_face->LoadStatus() == FontFace::kLoading) + RemoveFromLoadingFonts(font_face); + } + non_css_connected_faces_.clear(); + font_selector->FontFaceInvalidated(); +} + +bool FontFaceSetDocument::deleteForBinding(ScriptState*, + FontFace* font_face, + ExceptionState&) { + DCHECK(font_face); + if (!InActiveDocumentContext()) + return false; + HeapListHashSet<Member<FontFace>>::iterator it = + non_css_connected_faces_.find(font_face); + if (it != non_css_connected_faces_.end()) { + non_css_connected_faces_.erase(it); + CSSFontSelector* font_selector = + GetDocument()->GetStyleEngine().GetFontSelector(); + font_selector->GetFontFaceCache()->RemoveFontFace(font_face, false); + if (font_face->LoadStatus() == FontFace::kLoading) + RemoveFromLoadingFonts(font_face); + font_selector->FontFaceInvalidated(); + return true; + } + return false; +} + +bool FontFaceSetDocument::hasForBinding(ScriptState*, + FontFace* font_face, + ExceptionState&) const { + DCHECK(font_face); + if (!InActiveDocumentContext()) + return false; + return non_css_connected_faces_.Contains(font_face) || + IsCSSConnectedFontFace(font_face); +} + +const HeapListHashSet<Member<FontFace>>& +FontFaceSetDocument::CssConnectedFontFaceList() const { + Document* document = this->GetDocument(); + document->UpdateActiveStyle(); + return document->GetStyleEngine() + .GetFontSelector() + ->GetFontFaceCache() + ->CssConnectedFontFaces(); +} + +bool FontFaceSetDocument::IsCSSConnectedFontFace(FontFace* font_face) const { + return CssConnectedFontFaceList().Contains(font_face); +} + +size_t FontFaceSetDocument::size() const { + if (!InActiveDocumentContext()) + return non_css_connected_faces_.size(); + return CssConnectedFontFaceList().size() + non_css_connected_faces_.size(); +} + +void FontFaceSetDocument::FireDoneEventIfPossible() { + if (should_fire_loading_event_) + return; + if (!ShouldSignalReady()) + return; + Document* d = GetDocument(); + if (!d) + return; + + // If the layout was invalidated in between when we thought layout + // was updated and when we're ready to fire the event, just wait + // until after the next layout before firing events. + if (!d->View() || d->View()->NeedsLayout()) + return; + + if (is_loading_) { + FontFaceSetLoadEvent* done_event = nullptr; + FontFaceSetLoadEvent* error_event = nullptr; + done_event = FontFaceSetLoadEvent::CreateForFontFaces( + EventTypeNames::loadingdone, loaded_fonts_); + loaded_fonts_.clear(); + if (!failed_fonts_.IsEmpty()) { + error_event = FontFaceSetLoadEvent::CreateForFontFaces( + EventTypeNames::loadingerror, failed_fonts_); + failed_fonts_.clear(); + } + is_loading_ = false; + DispatchEvent(done_event); + if (error_event) + DispatchEvent(error_event); + } + + if (ready_->GetState() == ReadyProperty::kPending) + ready_->Resolve(this); +} + +ScriptPromise FontFaceSetDocument::load(ScriptState* script_state, + const String& font_string, + const String& text) { + if (!InActiveDocumentContext()) + return ScriptPromise(); + + Font font; + if (!ResolveFontStyle(font_string, font)) { + ScriptPromiseResolver* resolver = + ScriptPromiseResolver::Create(script_state); + ScriptPromise promise = resolver->Promise(); + resolver->Reject(DOMException::Create( + kSyntaxError, "Could not resolve '" + font_string + "' as a font.")); + return promise; + } + + FontFaceCache* font_face_cache = + GetDocument()->GetStyleEngine().GetFontSelector()->GetFontFaceCache(); + FontFaceArray faces; + for (const FontFamily* f = &font.GetFontDescription().Family(); f; + f = f->Next()) { + CSSSegmentedFontFace* segmented_font_face = + font_face_cache->Get(font.GetFontDescription(), f->Family()); + if (segmented_font_face) + segmented_font_face->Match(text, faces); + } + + LoadFontPromiseResolver* resolver = + LoadFontPromiseResolver::Create(faces, script_state); + ScriptPromise promise = resolver->Promise(); + // After this, resolver->promise() may return null. + resolver->LoadFonts(); + return promise; +} + +bool FontFaceSetDocument::check(const String& font_string, + const String& text, + ExceptionState& exception_state) { + if (!InActiveDocumentContext()) + return false; + + Font font; + if (!ResolveFontStyle(font_string, font)) { + exception_state.ThrowDOMException( + kSyntaxError, "Could not resolve '" + font_string + "' as a font."); + return false; + } + + CSSFontSelector* font_selector = + GetDocument()->GetStyleEngine().GetFontSelector(); + FontFaceCache* font_face_cache = font_selector->GetFontFaceCache(); + + bool has_loaded_faces = false; + for (const FontFamily* f = &font.GetFontDescription().Family(); f; + f = f->Next()) { + CSSSegmentedFontFace* face = + font_face_cache->Get(font.GetFontDescription(), f->Family()); + if (face) { + if (!face->CheckFont(text)) + return false; + has_loaded_faces = true; + } + } + if (has_loaded_faces) + return true; + for (const FontFamily* f = &font.GetFontDescription().Family(); f; + f = f->Next()) { + if (font_selector->IsPlatformFamilyMatchAvailable(font.GetFontDescription(), + f->Family())) + return true; + } + return false; +} + +bool FontFaceSetDocument::ResolveFontStyle(const String& font_string, + Font& font) { + if (font_string.IsEmpty()) + return false; + + // Interpret fontString in the same way as the 'font' attribute of + // CanvasRenderingContext2D. + MutableStylePropertySet* parsed_style = + MutableStylePropertySet::Create(kHTMLStandardMode); + CSSParser::ParseValue(parsed_style, CSSPropertyFont, font_string, true); + if (parsed_style->IsEmpty()) + return false; + + String font_value = parsed_style->GetPropertyValue(CSSPropertyFont); + if (font_value == "inherit" || font_value == "initial") + return false; + + RefPtr<ComputedStyle> style = ComputedStyle::Create(); + + FontFamily font_family; + font_family.SetFamily(kDefaultFontFamily); + + FontDescription default_font_description; + default_font_description.SetFamily(font_family); + default_font_description.SetSpecifiedSize(kDefaultFontSize); + default_font_description.SetComputedSize(kDefaultFontSize); + + style->SetFontDescription(default_font_description); + + style->GetFont().Update(style->GetFont().GetFontSelector()); + + GetDocument()->UpdateActiveStyle(); + GetDocument()->EnsureStyleResolver().ComputeFont(style.Get(), *parsed_style); + + font = style->GetFont(); + font.Update(GetDocument()->GetStyleEngine().GetFontSelector()); + return true; +} + +void FontFaceSetDocument::FontLoadHistogram::UpdateStatus(FontFace* font_face) { + if (status_ == kReported) + return; + if (font_face->HadBlankText()) + status_ = kHadBlankText; + else if (status_ == kNoWebFonts) + status_ = kDidNotHaveBlankText; +} + +void FontFaceSetDocument::FontLoadHistogram::Record() { + if (!recorded_) { + recorded_ = true; + DEFINE_STATIC_LOCAL(CustomCountHistogram, web_fonts_in_page_histogram, + ("WebFont.WebFontsInPage", 1, 100, 50)); + web_fonts_in_page_histogram.Count(count_); + } + if (status_ == kHadBlankText || status_ == kDidNotHaveBlankText) { + DEFINE_STATIC_LOCAL(EnumerationHistogram, had_blank_text_histogram, + ("WebFont.HadBlankText", 2)); + had_blank_text_histogram.Count(status_ == kHadBlankText ? 1 : 0); + status_ = kReported; + } +} + +FontFaceSetDocument* FontFaceSetDocument::From(Document& document) { + FontFaceSetDocument* fonts = static_cast<FontFaceSetDocument*>( + Supplement<Document>::From(document, SupplementName())); + if (!fonts) { + fonts = FontFaceSetDocument::Create(document); + Supplement<Document>::ProvideTo(document, SupplementName(), fonts); + } + + return fonts; +} + +void FontFaceSetDocument::DidLayout(Document& document) { + if (FontFaceSetDocument* fonts = static_cast<FontFaceSetDocument*>( + Supplement<Document>::From(document, SupplementName()))) + fonts->DidLayout(); +} + +size_t FontFaceSetDocument::ApproximateBlankCharacterCount(Document& document) { + if (FontFaceSetDocument* fonts = static_cast<FontFaceSetDocument*>( + Supplement<Document>::From(document, SupplementName()))) + return fonts->ApproximateBlankCharacterCount(); + return 0; +} + +FontFaceSetIterable::IterationSource* FontFaceSetDocument::StartIteration( + ScriptState*, + ExceptionState&) { + // Setlike should iterate each item in insertion order, and items should + // be keep on up to date. But since blink does not have a way to hook up CSS + // modification, take a snapshot here, and make it ordered as follows. + HeapVector<Member<FontFace>> font_faces; + if (InActiveDocumentContext()) { + const HeapListHashSet<Member<FontFace>>& css_connected_faces = + CssConnectedFontFaceList(); + font_faces.ReserveInitialCapacity(css_connected_faces.size() + + non_css_connected_faces_.size()); + for (const auto& font_face : css_connected_faces) + font_faces.push_back(font_face); + for (const auto& font_face : non_css_connected_faces_) + font_faces.push_back(font_face); + } + return new IterationSource(font_faces); +} + +bool FontFaceSetDocument::IterationSource::Next(ScriptState*, + Member<FontFace>& key, + Member<FontFace>& value, + ExceptionState&) { + if (font_faces_.size() <= index_) + return false; + key = value = font_faces_[index_++]; + return true; +} + +DEFINE_TRACE(FontFaceSetDocument) { + visitor->Trace(ready_); + visitor->Trace(loading_fonts_); + visitor->Trace(loaded_fonts_); + visitor->Trace(failed_fonts_); + visitor->Trace(non_css_connected_faces_); + visitor->Trace(async_runner_); + EventTargetWithInlineData::Trace(visitor); + Supplement<Document>::Trace(visitor); + SuspendableObject::Trace(visitor); + FontFace::LoadFontCallback::Trace(visitor); + FontFaceSet::Trace(visitor); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/css/FontFaceSetDocument.h b/third_party/WebKit/Source/core/css/FontFaceSetDocument.h new file mode 100644 index 0000000..7ce4df7 --- /dev/null +++ b/third_party/WebKit/Source/core/css/FontFaceSetDocument.h
@@ -0,0 +1,166 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +#ifndef FontFaceSetDocument_h +#define FontFaceSetDocument_h + +#include "bindings/core/v8/Iterable.h" +#include "bindings/core/v8/ScriptPromise.h" +#include "core/css/FontFace.h" +#include "core/css/FontFaceSet.h" +#include "core/dom/Document.h" +#include "core/dom/SuspendableObject.h" +#include "core/events/EventListener.h" +#include "core/events/EventTarget.h" +#include "platform/AsyncMethodRunner.h" +#include "platform/heap/Handle.h" +#include "platform/wtf/Allocator.h" +#include "platform/wtf/Vector.h" + +// Mac OS X 10.6 SDK defines check() macro that interferes with our check() +// method +#ifdef check +#undef check +#endif + +namespace blink { + +class ExceptionState; +class Font; +class FontFaceCache; +class ExecutionContext; + +class CORE_EXPORT FontFaceSetDocument final + : public FontFaceSet, + public Supplement<Document>, + public SuspendableObject, + public FontFace::LoadFontCallback { + USING_GARBAGE_COLLECTED_MIXIN(FontFaceSetDocument); + WTF_MAKE_NONCOPYABLE(FontFaceSetDocument); + + public: + ~FontFaceSetDocument() override; + + bool check(const String& font, const String& text, ExceptionState&) override; + ScriptPromise load(ScriptState*, + const String& font, + const String& text) override; + ScriptPromise ready(ScriptState*) override; + + FontFaceSet* addForBinding(ScriptState*, FontFace*, ExceptionState&) override; + void clearForBinding(ScriptState*, ExceptionState&) override; + bool deleteForBinding(ScriptState*, FontFace*, ExceptionState&) override; + bool hasForBinding(ScriptState*, FontFace*, ExceptionState&) const override; + + size_t size() const override; + AtomicString status() const override; + + ExecutionContext* GetExecutionContext() const override; + + Document* GetDocument() const; + + void DidLayout(); + void BeginFontLoading(FontFace*); + + // FontFace::LoadFontCallback + void NotifyLoaded(FontFace*) override; + void NotifyError(FontFace*) override; + + size_t ApproximateBlankCharacterCount() const; + + // SuspendableObject + void Suspend() override; + void Resume() override; + void ContextDestroyed(ExecutionContext*) override; + + static FontFaceSetDocument* From(Document&); + static void DidLayout(Document&); + static size_t ApproximateBlankCharacterCount(Document&); + + static const char* SupplementName() { return "FontFaceSetDocument"; } + + void AddFontFacesToFontFaceCache(FontFaceCache*); + + DECLARE_VIRTUAL_TRACE(); + + private: + FontFaceSetIterable::IterationSource* StartIteration( + ScriptState*, + ExceptionState&) override; + + static FontFaceSetDocument* Create(Document& document) { + return new FontFaceSetDocument(document); + } + + class FontLoadHistogram { + DISALLOW_NEW(); + + public: + enum Status { kNoWebFonts, kHadBlankText, kDidNotHaveBlankText, kReported }; + FontLoadHistogram() : status_(kNoWebFonts), count_(0), recorded_(false) {} + void IncrementCount() { count_++; } + void UpdateStatus(FontFace*); + void Record(); + + private: + Status status_; + int count_; + bool recorded_; + }; + + explicit FontFaceSetDocument(Document&); + + bool InActiveDocumentContext() const; + void AddToLoadingFonts(FontFace*); + void RemoveFromLoadingFonts(FontFace*); + void FireLoadingEvent(); + void FireDoneEventIfPossible(); + bool ResolveFontStyle(const String&, Font&); + void HandlePendingEventsAndPromisesSoon(); + void HandlePendingEventsAndPromises(); + const HeapListHashSet<Member<FontFace>>& CssConnectedFontFaceList() const; + bool IsCSSConnectedFontFace(FontFace*) const; + bool ShouldSignalReady() const; + + using ReadyProperty = ScriptPromiseProperty<Member<FontFaceSetDocument>, + Member<FontFaceSetDocument>, + Member<DOMException>>; + + HeapHashSet<Member<FontFace>> loading_fonts_; + bool should_fire_loading_event_; + bool is_loading_; + Member<ReadyProperty> ready_; + FontFaceArray loaded_fonts_; + FontFaceArray failed_fonts_; + HeapListHashSet<Member<FontFace>> non_css_connected_faces_; + + Member<AsyncMethodRunner<FontFaceSetDocument>> async_runner_; + + FontLoadHistogram histogram_; +}; + +} // namespace blink + +#endif // FontFaceSetDocument_h
diff --git a/third_party/WebKit/Source/core/css/FontFaceSource.cpp b/third_party/WebKit/Source/core/css/FontFaceSource.cpp index 4d4dc4a..e059acd0 100644 --- a/third_party/WebKit/Source/core/css/FontFaceSource.cpp +++ b/third_party/WebKit/Source/core/css/FontFaceSource.cpp
@@ -4,12 +4,12 @@ #include "core/css/FontFaceSource.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" namespace blink { FontFaceSet* FontFaceSource::fonts(Document& document) { - return FontFaceSet::From(document); + return FontFaceSetDocument::From(document); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp b/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp index 430d30ac..4a16fb18 100644 --- a/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp +++ b/third_party/WebKit/Source/core/css/OffscreenFontSelector.cpp
@@ -7,7 +7,6 @@ #include "build/build_config.h" #include "core/css/CSSSegmentedFontFace.h" #include "core/css/CSSValueList.h" -#include "core/css/FontFaceSet.h" #include "core/css/resolver/StyleResolver.h" #include "core/frame/LocalFrame.h" #include "core/frame/Settings.h"
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 5fedacd..26ca7f2 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -54,7 +54,7 @@ #include "core/css/CSSStyleDeclaration.h" #include "core/css/CSSStyleSheet.h" #include "core/css/CSSTiming.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/css/MediaQueryMatcher.h" #include "core/css/PropertyRegistry.h" #include "core/css/StylePropertySet.h" @@ -6996,8 +6996,9 @@ // Cannot trace in Supplementable<Document> as it is part of platform/ and // thus cannot refer to ScriptWrappableVisitor. visitor->TraceWrappersWithManualWriteBarrier( - static_cast<FontFaceSet*>(Supplementable<Document>::supplements_.at( - FontFaceSet::SupplementName()))); + static_cast<FontFaceSetDocument*>( + Supplementable<Document>::supplements_.at( + FontFaceSetDocument::SupplementName()))); ContainerNode::TraceWrappers(visitor); }
diff --git a/third_party/WebKit/Source/core/dom/RangeTest.cpp b/third_party/WebKit/Source/core/dom/RangeTest.cpp index 219baeaa..64ca6ff 100644 --- a/third_party/WebKit/Source/core/dom/RangeTest.cpp +++ b/third_party/WebKit/Source/core/dom/RangeTest.cpp
@@ -8,7 +8,7 @@ #include "bindings/core/v8/StringOrArrayBufferOrArrayBufferView.h" #include "bindings/core/v8/V8BindingForTesting.h" #include "core/css/FontFaceDescriptors.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/dom/Element.h" #include "core/dom/NodeList.h" #include "core/dom/Text.h" @@ -271,8 +271,8 @@ ScriptState* script_state = ToScriptStateForMainWorld(&page_holder.GetFrame()); DummyExceptionStateForTesting exception_state; - FontFaceSet::From(document)->addForBinding(script_state, ahem, - exception_state); + FontFaceSetDocument::From(document)->addForBinding(script_state, ahem, + exception_state); } TEST_F(RangeTest, BoundingRectMustIndependentFromSelection) {
diff --git a/third_party/WebKit/Source/core/exported/WebAssociatedURLLoaderImpl.cpp b/third_party/WebKit/Source/core/exported/WebAssociatedURLLoaderImpl.cpp index 15cafc71..10d296d 100644 --- a/third_party/WebKit/Source/core/exported/WebAssociatedURLLoaderImpl.cpp +++ b/third_party/WebKit/Source/core/exported/WebAssociatedURLLoaderImpl.cpp
@@ -41,7 +41,6 @@ #include "platform/Timer.h" #include "platform/exported/WrappedResourceRequest.h" #include "platform/exported/WrappedResourceResponse.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/FetchUtils.h" #include "platform/loader/fetch/ResourceError.h" #include "platform/loader/fetch/ResourceLoaderOptions.h" @@ -50,6 +49,7 @@ #include "platform/wtf/HashSet.h" #include "platform/wtf/PtrUtil.h" #include "platform/wtf/text/WTFString.h" +#include "public/platform/WebCORS.h" #include "public/platform/WebHTTPHeaderVisitor.h" #include "public/platform/WebString.h" #include "public/platform/WebURLError.h" @@ -222,14 +222,13 @@ return; } - HTTPHeaderSet exposed_headers; - CrossOriginAccessControl::ExtractCorsExposedHeaderNamesList(response, - exposed_headers); - HTTPHeaderSet blocked_headers; + WebCORS::HTTPHeaderSet exposed_headers; + WebCORS::ExtractCorsExposedHeaderNamesList(WrappedResourceResponse(response), + exposed_headers); + WebCORS::HTTPHeaderSet blocked_headers; for (const auto& header : response.HttpHeaderFields()) { if (FetchUtils::IsForbiddenResponseHeaderName(header.key) || - (!CrossOriginAccessControl::IsOnAccessControlResponseHeaderWhitelist( - header.key) && + (!WebCORS::IsOnAccessControlResponseHeaderWhitelist(header.key) && !exposed_headers.Contains(header.key))) blocked_headers.insert(header.key); }
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp index a55a5a4..89e4b9f 100644 --- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp +++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -31,7 +31,7 @@ #include "core/HTMLNames.h" #include "core/MediaTypeNames.h" #include "core/animation/DocumentAnimations.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/dom/AXObjectCache.h" #include "core/dom/DOMNodeIds.h" #include "core/dom/ElementVisibilityObserver.h" @@ -1013,9 +1013,9 @@ value->SetInteger("contentsHeightAfterLayout", GetLayoutViewItem().DocumentRect().Height()); value->SetInteger("visibleHeight", VisibleHeight()); - value->SetInteger( - "approximateBlankCharacterCount", - FontFaceSet::ApproximateBlankCharacterCount(*frame_->GetDocument())); + value->SetInteger("approximateBlankCharacterCount", + FontFaceSetDocument::ApproximateBlankCharacterCount( + *frame_->GetDocument())); return value; } @@ -2026,9 +2026,10 @@ if (!layer->AncestorOverflowLayer()) continue; - StickyConstraintsMap constraints_map = layer->AncestorOverflowLayer() - ->GetScrollableArea() - ->GetStickyConstraintsMap(); + const StickyConstraintsMap& constraints_map = + layer->AncestorOverflowLayer() + ->GetScrollableArea() + ->GetStickyConstraintsMap(); if (constraints_map.Contains(layer) && !constraints_map.at(layer).HasAncestorStickyElement()) { // TODO(skobes): Resolve circular dependency between scroll offset and @@ -2569,7 +2570,7 @@ DCHECK(frame_->GetDocument()); - FontFaceSet::DidLayout(*frame_->GetDocument()); + FontFaceSetDocument::DidLayout(*frame_->GetDocument()); // Cursor update scheduling is done by the local root, which is the main frame // if there are no RemoteFrame ancestors in the frame tree. Use of // localFrameRoot() is discouraged but will change when cursor update
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp index f2687a8..7099fbc 100644 --- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.cpp
@@ -7,7 +7,7 @@ #include "bindings/core/v8/StringOrArrayBufferOrArrayBufferView.h" #include "bindings/core/v8/V8BindingForCore.h" #include "core/css/FontFaceDescriptors.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/html/HTMLIFrameElement.h" #include "core/typed_arrays/DOMArrayBuffer.h" #include "platform/loader/fetch/MemoryCache.h" @@ -89,7 +89,7 @@ ScriptState* script_state = ToScriptStateForMainWorld(&page_holder_->GetFrame()); DummyExceptionStateForTesting exception_state; - FontFaceSet::From(GetDocument()) + FontFaceSetDocument::From(GetDocument()) ->addForBinding(script_state, ahem, exception_state); }
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp index 439838f..ed7872e 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMapping.cpp
@@ -298,9 +298,15 @@ void CompositedLayerMapping::UpdateStickyConstraints( const ComputedStyle& style) { + WebLayerStickyPositionConstraint web_constraint; + if (!UsesCompositedStickyPosition()) { + // Clear the previous sticky position constraint - if set. + graphics_layer_->SetStickyPositionConstraint(web_constraint); + return; + } + const PaintLayer* ancestor_overflow_layer = owning_layer_.AncestorOverflowLayer(); - WebLayerStickyPositionConstraint web_constraint; const StickyConstraintsMap& constraints_map = ancestor_overflow_layer->GetScrollableArea()->GetStickyConstraintsMap(); const StickyPositionScrollingConstraints& constraints = @@ -1097,8 +1103,7 @@ graphics_layer_parent_location); UpdateContentsOffsetInCompositingLayer( snapped_offset_from_composited_ancestor, graphics_layer_parent_location); - if (UsesCompositedStickyPosition()) - UpdateStickyConstraints(GetLayoutObject().StyleRef()); + UpdateStickyConstraints(GetLayoutObject().StyleRef()); UpdateSquashingLayerGeometry( graphics_layer_parent_location, compositing_container, squashed_layers_, squashing_layer_.get(),
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp index 858bdc0..37da42e 100644 --- a/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp +++ b/third_party/WebKit/Source/core/layout/compositing/CompositedLayerMappingTest.cpp
@@ -2101,4 +2101,53 @@ target_graphics_layer->ContentLayer()->TransformedRasterizationAllowed()); } +// This tests that when the scroller becomes no longer scrollable if a sticky +// element is promoted for another reason we do remove its composited sticky +// constraint as it doesn't need to move on the compositor. +TEST_P(CompositedLayerMappingTest, CompositedStickyConstraintRemovedAndAdded) { + SetBodyInnerHTML( + "<style>" + ".scroller { overflow: auto; height: 200px; }" + ".sticky { position: sticky; top: 0; width: 10px; height: 10px; }" + ".composited { will-change: transform; }" + "</style>" + "<div class='composited scroller'>" + " <div id='sticky' class='composited sticky'></div>" + " <div id='spacer' style='height: 2000px;'></div>" + "</div>"); + GetDocument().View()->UpdateAllLifecyclePhases(); + PaintLayer* sticky_layer = + ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"))->Layer(); + EXPECT_TRUE(sticky_layer->GraphicsLayerBacking() + ->PlatformLayer() + ->StickyPositionConstraint() + .is_sticky); + + // Make the scroller no longer scrollable. + GetDocument().getElementById("spacer")->setAttribute(HTMLNames::styleAttr, + "height: 0;"); + GetDocument().View()->UpdateAllLifecyclePhases(); + + // The sticky position element is composited due to a compositing trigger but + // should no longer have a sticky position constraint on the compositor. + sticky_layer = + ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"))->Layer(); + EXPECT_FALSE(sticky_layer->GraphicsLayerBacking() + ->PlatformLayer() + ->StickyPositionConstraint() + .is_sticky); + + // Make the scroller scrollable again. + GetDocument().getElementById("spacer")->setAttribute(HTMLNames::styleAttr, + "height: 2000px;"); + GetDocument().View()->UpdateAllLifecyclePhases(); + + sticky_layer = + ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"))->Layer(); + EXPECT_TRUE(sticky_layer->GraphicsLayerBacking() + ->PlatformLayer() + ->StickyPositionConstraint() + .is_sticky); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp index a08bf3f7..7ba28314 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -50,7 +50,8 @@ #include "core/page/Page.h" #include "core/probe/CoreProbes.h" #include "platform/SharedBuffer.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" +#include "platform/exported/WrappedResourceRequest.h" +#include "platform/exported/WrappedResourceResponse.h" #include "platform/loader/fetch/FetchParameters.h" #include "platform/loader/fetch/FetchUtils.h" #include "platform/loader/fetch/Resource.h" @@ -64,6 +65,8 @@ #include "platform/wtf/PtrUtil.h" #include "platform/wtf/WeakPtr.h" #include "public/platform/Platform.h" +#include "public/platform/WebCORS.h" +#include "public/platform/WebSecurityOrigin.h" #include "public/platform/WebURLRequest.h" namespace blink { @@ -348,9 +351,11 @@ void DocumentThreadableLoader::LoadPreflightRequest( const ResourceRequest& actual_request, const ResourceLoaderOptions& actual_options) { - ResourceRequest preflight_request = - CrossOriginAccessControl::CreateAccessControlPreflightRequest( - actual_request); + WebURLRequest web_url_request = WebCORS::CreateAccessControlPreflightRequest( + WrappedResourceRequest(actual_request)); + + ResourceRequest& preflight_request = + web_url_request.ToMutableResourceRequest(); // TODO(tyoshino): Call prepareCrossOriginRequest(preflightRequest) to // also set the referrer header. @@ -624,15 +629,14 @@ redirect_response, resource); } - CrossOriginAccessControl::RedirectStatus redirect_status = - CrossOriginAccessControl::CheckRedirectLocation(new_url); - if (redirect_status != CrossOriginAccessControl::kRedirectSuccess) { + WebCORS::RedirectStatus redirect_status = + WebCORS::CheckRedirectLocation(new_url); + if (redirect_status != WebCORS::RedirectStatus::kRedirectSuccess) { StringBuilder builder; builder.Append("Redirect from '"); builder.Append(original_url.GetString()); builder.Append("' has been blocked by CORS policy: "); - CrossOriginAccessControl::RedirectErrorString(builder, redirect_status, - new_url); + builder.Append(WebCORS::RedirectErrorString(redirect_status, new_url)); DispatchDidFailAccessControlCheck( ResourceError::CancelledDueToAccessCheckError( original_url, ResourceRequestBlockedReason::kOther, @@ -643,20 +647,20 @@ if (cors_flag_) { // The redirect response must pass the access control check if the CORS // flag is set. - CrossOriginAccessControl::AccessStatus cors_status = - CrossOriginAccessControl::CheckAccess( - redirect_response, new_request.GetFetchCredentialsMode(), - GetSecurityOrigin()); - if (cors_status != CrossOriginAccessControl::kAccessAllowed) { + WebCORS::AccessStatus cors_status = + WebCORS::CheckAccess(WrappedResourceResponse(redirect_response), + new_request.GetFetchCredentialsMode(), + WebSecurityOrigin(GetSecurityOrigin())); + if (cors_status != WebCORS::AccessStatus::kAccessAllowed) { StringBuilder builder; builder.Append("Redirect from '"); builder.Append(original_url.GetString()); builder.Append("' to '"); builder.Append(new_url.GetString()); builder.Append("' has been blocked by CORS policy: "); - CrossOriginAccessControl::AccessControlErrorString( - builder, cors_status, redirect_response, GetSecurityOrigin(), - request_context_); + builder.Append(WebCORS::AccessControlErrorString( + cors_status, WrappedResourceResponse(redirect_response), + WebSecurityOrigin(GetSecurityOrigin()), request_context_)); DispatchDidFailAccessControlCheck( ResourceError::CancelledDueToAccessCheckError( original_url, ResourceRequestBlockedReason::kOther, @@ -775,40 +779,41 @@ const ResourceResponse& response) { String access_control_error_description; - CrossOriginAccessControl::AccessStatus cors_status = - CrossOriginAccessControl::CheckAccess( - response, actual_request_.GetFetchCredentialsMode(), - GetSecurityOrigin()); - if (cors_status != CrossOriginAccessControl::kAccessAllowed) { + WebCORS::AccessStatus cors_status = + WebCORS::CheckAccess(WrappedResourceResponse(response), + actual_request_.GetFetchCredentialsMode(), + WebSecurityOrigin(GetSecurityOrigin())); + if (cors_status != WebCORS::AccessStatus::kAccessAllowed) { StringBuilder builder; builder.Append( "Response to preflight request doesn't pass access " "control check: "); - CrossOriginAccessControl::AccessControlErrorString( - builder, cors_status, response, GetSecurityOrigin(), request_context_); + builder.Append(WebCORS::AccessControlErrorString( + cors_status, WrappedResourceResponse(response), + WebSecurityOrigin(GetSecurityOrigin()), request_context_)); HandlePreflightFailure(response.Url(), builder.ToString()); return; } - CrossOriginAccessControl::PreflightStatus preflight_status = - CrossOriginAccessControl::CheckPreflight(response); - if (preflight_status != CrossOriginAccessControl::kPreflightSuccess) { - StringBuilder builder; - CrossOriginAccessControl::PreflightErrorString(builder, preflight_status, - response); - HandlePreflightFailure(response.Url(), builder.ToString()); + WebCORS::PreflightStatus preflight_status = + WebCORS::CheckPreflight(WrappedResourceResponse(response)); + if (preflight_status != WebCORS::PreflightStatus::kPreflightSuccess) { + HandlePreflightFailure( + response.Url(), + WebCORS::PreflightErrorString(preflight_status, + WrappedResourceResponse(response))); return; } if (actual_request_.IsExternalRequest()) { - CrossOriginAccessControl::PreflightStatus external_preflight_status = - CrossOriginAccessControl::CheckExternalPreflight(response); + WebCORS::PreflightStatus external_preflight_status = + WebCORS::CheckExternalPreflight(WrappedResourceResponse(response)); if (external_preflight_status != - CrossOriginAccessControl::kPreflightSuccess) { - StringBuilder builder; - CrossOriginAccessControl::PreflightErrorString( - builder, external_preflight_status, response); - HandlePreflightFailure(response.Url(), builder.ToString()); + WebCORS::PreflightStatus::kPreflightSuccess) { + HandlePreflightFailure( + response.Url(), + WebCORS::PreflightErrorString(external_preflight_status, + WrappedResourceResponse(response))); return; } } @@ -886,9 +891,10 @@ response.ResponseTypeViaServiceWorker() == mojom::FetchResponseType::kOpaque) { StringBuilder builder; - CrossOriginAccessControl::AccessControlErrorString( - builder, CrossOriginAccessControl::kInvalidResponse, response, - GetSecurityOrigin(), request_context_); + builder.Append(WebCORS::AccessControlErrorString( + WebCORS::AccessStatus::kInvalidResponse, + WrappedResourceResponse(response), + WebSecurityOrigin(GetSecurityOrigin()), request_context_)); DispatchDidFailAccessControlCheck( ResourceError::CancelledDueToAccessCheckError( response.Url(), ResourceRequestBlockedReason::kOther, @@ -916,19 +922,17 @@ fallback_request_for_service_worker_ = ResourceRequest(); if (IsCORSEnabledRequestMode(request_mode) && cors_flag_) { - CrossOriginAccessControl::AccessStatus cors_status = - CrossOriginAccessControl::CheckAccess(response, credentials_mode, - GetSecurityOrigin()); - if (cors_status != CrossOriginAccessControl::kAccessAllowed) { + WebCORS::AccessStatus cors_status = WebCORS::CheckAccess( + WrappedResourceResponse(response), credentials_mode, + WebSecurityOrigin(GetSecurityOrigin())); + if (cors_status != WebCORS::AccessStatus::kAccessAllowed) { ReportResponseReceived(identifier, response); - StringBuilder builder; - CrossOriginAccessControl::AccessControlErrorString( - builder, cors_status, response, GetSecurityOrigin(), - request_context_); DispatchDidFailAccessControlCheck( ResourceError::CancelledDueToAccessCheckError( response.Url(), ResourceRequestBlockedReason::kOther, - builder.ToString())); + WebCORS::AccessControlErrorString( + cors_status, WrappedResourceResponse(response), + WebSecurityOrigin(GetSecurityOrigin()), request_context_))); return; } } @@ -1246,7 +1250,7 @@ return !cors_flag_ && GetSecurityOrigin()->CanRequest(url); } -const SecurityOrigin* DocumentThreadableLoader::GetSecurityOrigin() const { +SecurityOrigin* DocumentThreadableLoader::GetSecurityOrigin() const { return security_origin_ ? security_origin_.Get() : loading_context_->GetFetchContext()->GetSecurityOrigin();
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h index a1a1694a..521d0b4 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -193,7 +193,7 @@ Member<RawResource> resource_; // End of ResourceOwner re-implementation, see above. - const SecurityOrigin* GetSecurityOrigin() const; + SecurityOrigin* GetSecurityOrigin() const; // TODO(kinuko): Remove dependency to document. Document* GetDocument() const;
diff --git a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp index 35e9ca8..f8f0f8c 100644 --- a/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp +++ b/third_party/WebKit/Source/core/offscreencanvas/OffscreenCanvas.cpp
@@ -265,7 +265,7 @@ image_buffer_ = ImageBuffer::Create(std::move(surface)); - if (needs_matrix_clip_restore_) { + if (image_buffer_ && needs_matrix_clip_restore_) { needs_matrix_clip_restore_ = false; context_->RestoreCanvasMatrixClipStack(image_buffer_->Canvas()); }
diff --git a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp index 3e80b9ab..1af03ea 100644 --- a/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp +++ b/third_party/WebKit/Source/core/paint/FirstMeaningfulPaintDetector.cpp
@@ -4,7 +4,7 @@ #include "core/paint/FirstMeaningfulPaintDetector.h" -#include "core/css/FontFaceSet.h" +#include "core/css/FontFaceSetDocument.h" #include "core/dom/TaskRunnerHelper.h" #include "core/paint/PaintTiming.h" #include "platform/Histogram.h" @@ -72,7 +72,7 @@ // If the page has many blank characters, the significance value is // accumulated until the text become visible. int approximate_blank_character_count = - FontFaceSet::ApproximateBlankCharacterCount(*GetDocument()); + FontFaceSetDocument::ApproximateBlankCharacterCount(*GetDocument()); if (approximate_blank_character_count > kBlankCharactersThreshold) { accumulated_significance_while_having_blank_text_ += significance; } else {
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index 4d29d09..de90dc0 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -65,7 +65,7 @@ #include "platform/bindings/DOMWrapperWorld.h" #include "platform/bindings/ScriptState.h" #include "platform/blob/BlobData.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" +#include "platform/exported/WrappedResourceResponse.h" #include "platform/loader/fetch/FetchInitiatorTypeNames.h" #include "platform/loader/fetch/FetchUtils.h" #include "platform/loader/fetch/ResourceError.h" @@ -81,6 +81,7 @@ #include "platform/wtf/AutoReset.h" #include "platform/wtf/StdLibExtras.h" #include "platform/wtf/text/CString.h" +#include "public/platform/WebCORS.h" #include "public/platform/WebURLRequest.h" namespace blink { @@ -1413,9 +1414,9 @@ StringBuilder string_builder; - HTTPHeaderSet access_control_expose_header_set; - CrossOriginAccessControl::ExtractCorsExposedHeaderNamesList( - response_, access_control_expose_header_set); + WebCORS::HTTPHeaderSet access_control_expose_header_set; + WebCORS::ExtractCorsExposedHeaderNamesList(WrappedResourceResponse(response_), + access_control_expose_header_set); HTTPHeaderMap::const_iterator end = response_.HttpHeaderFields().end(); for (HTTPHeaderMap::const_iterator it = response_.HttpHeaderFields().begin(); @@ -1430,8 +1431,7 @@ continue; if (!same_origin_request_ && - !CrossOriginAccessControl::IsOnAccessControlResponseHeaderWhitelist( - it->key) && + !WebCORS::IsOnAccessControlResponseHeaderWhitelist(it->key) && !access_control_expose_header_set.Contains(it->key)) continue; @@ -1459,13 +1459,12 @@ return g_null_atom; } - HTTPHeaderSet access_control_expose_header_set; - CrossOriginAccessControl::ExtractCorsExposedHeaderNamesList( - response_, access_control_expose_header_set); + WebCORS::HTTPHeaderSet access_control_expose_header_set; + WebCORS::ExtractCorsExposedHeaderNamesList(WrappedResourceResponse(response_), + access_control_expose_header_set); if (!same_origin_request_ && - !CrossOriginAccessControl::IsOnAccessControlResponseHeaderWhitelist( - name) && + !WebCORS::IsOnAccessControlResponseHeaderWhitelist(name) && !access_control_expose_header_set.Contains(name)) { LogConsoleError(GetExecutionContext(), "Refused to get unsafe header \"" + name + "\"");
diff --git a/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp b/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp index d02266709..f9ea1d07 100644 --- a/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp +++ b/third_party/WebKit/Source/modules/cachestorage/CacheStorage.cpp
@@ -14,6 +14,7 @@ #include "modules/cachestorage/CacheStorageError.h" #include "modules/fetch/Request.h" #include "modules/fetch/Response.h" +#include "platform/HTTPNames.h" #include "platform/bindings/ScriptState.h" #include "platform/wtf/PtrUtil.h" #include "public/platform/modules/serviceworker/WebServiceWorkerCacheError.h"
diff --git a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp index 47ddb452..e6c2fdc 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
@@ -31,8 +31,8 @@ #include "platform/HTTPNames.h" #include "platform/bindings/ScriptState.h" #include "platform/bindings/V8ThrowException.h" +#include "platform/exported/WrappedResourceResponse.h" #include "platform/loader/SubresourceIntegrity.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/FetchUtils.h" #include "platform/loader/fetch/ResourceError.h" #include "platform/loader/fetch/ResourceLoaderOptions.h" @@ -46,6 +46,7 @@ #include "platform/wtf/HashSet.h" #include "platform/wtf/Vector.h" #include "platform/wtf/text/WTFString.h" +#include "public/platform/WebCORS.h" #include "public/platform/WebURLRequest.h" namespace blink { @@ -468,9 +469,9 @@ tainted_response = response_data->CreateBasicFilteredResponse(); break; case FetchRequestData::kCORSTainting: { - HTTPHeaderSet header_names; - CrossOriginAccessControl::ExtractCorsExposedHeaderNamesList( - response, header_names); + WebCORS::HTTPHeaderSet header_names; + WebCORS::ExtractCorsExposedHeaderNamesList( + WrappedResourceResponse(response), header_names); tainted_response = response_data->CreateCORSFilteredResponse(header_names); break;
diff --git a/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp b/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp index f0a13e0..b8a4d21 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchResponseData.cpp
@@ -7,8 +7,8 @@ #include "core/typed_arrays/DOMArrayBuffer.h" #include "modules/fetch/BodyStreamBuffer.h" #include "modules/fetch/FetchHeaderList.h" +#include "platform/HTTPNames.h" #include "platform/bindings/ScriptState.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/FetchUtils.h" #include "platform/wtf/PtrUtil.h" #include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h" @@ -43,7 +43,8 @@ return web_type; } -WebVector<WebString> HeaderSetToWebVector(const HTTPHeaderSet& headers) { +WebVector<WebString> HeaderSetToWebVector( + const WebCORS::HTTPHeaderSet& headers) { // Can't just pass *headers to the WebVector constructor because HashSet // iterators are not stl iterator compatible. WebVector<WebString> result(static_cast<size_t>(headers.size())); @@ -96,18 +97,18 @@ FetchResponseData* FetchResponseData::CreateCORSFilteredResponse() const { DCHECK_EQ(type_, kDefaultType); - HTTPHeaderSet access_control_expose_header_set; + WebCORS::HTTPHeaderSet access_control_expose_header_set; String access_control_expose_headers; if (header_list_->Get(HTTPNames::Access_Control_Expose_Headers, access_control_expose_headers)) { - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( + WebCORS::ParseAccessControlExposeHeadersAllowList( access_control_expose_headers, access_control_expose_header_set); } return CreateCORSFilteredResponse(access_control_expose_header_set); } FetchResponseData* FetchResponseData::CreateCORSFilteredResponse( - const HTTPHeaderSet& exposed_headers) const { + const WebCORS::HTTPHeaderSet& exposed_headers) const { DCHECK_EQ(type_, kDefaultType); // "A CORS filtered response is a filtered response whose type is |CORS|, // header list excludes all headers in internal response's header list, @@ -122,8 +123,7 @@ for (const auto& header : header_list_->List()) { const String& name = header.first; const bool explicitly_exposed = exposed_headers.Contains(name); - if (CrossOriginAccessControl::IsOnAccessControlResponseHeaderWhitelist( - name) || + if (WebCORS::IsOnAccessControlResponseHeaderWhitelist(name) || (explicitly_exposed && !FetchUtils::IsForbiddenResponseHeaderName(name))) { if (explicitly_exposed)
diff --git a/third_party/WebKit/Source/modules/fetch/FetchResponseData.h b/third_party/WebKit/Source/modules/fetch/FetchResponseData.h index 707814c..88a9fd04 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchResponseData.h +++ b/third_party/WebKit/Source/modules/fetch/FetchResponseData.h
@@ -8,12 +8,12 @@ #include <memory> #include "modules/ModulesExport.h" #include "platform/heap/Handle.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/weborigin/KURL.h" #include "platform/wtf/PassRefPtr.h" #include "platform/wtf/Time.h" #include "platform/wtf/Vector.h" #include "platform/wtf/text/AtomicString.h" +#include "public/platform/WebCORS.h" #include "public/platform/modules/fetch/fetch_api_request.mojom-blink.h" #include "public/platform/modules/serviceworker/WebServiceWorkerRequest.h" @@ -60,7 +60,7 @@ // Creates a CORS filtered response with an explicit set of exposed header // names. FetchResponseData* CreateCORSFilteredResponse( - const HTTPHeaderSet& exposed_headers) const; + const WebCORS::HTTPHeaderSet& exposed_headers) const; FetchResponseData* CreateOpaqueFilteredResponse() const; FetchResponseData* CreateOpaqueRedirectFilteredResponse() const; @@ -84,7 +84,7 @@ String InternalMIMEType() const; Time ResponseTime() const { return response_time_; } String CacheStorageCacheName() const { return cache_storage_cache_name_; } - const HTTPHeaderSet& CorsExposedHeaderNames() const { + const WebCORS::HTTPHeaderSet& CorsExposedHeaderNames() const { return cors_exposed_header_names_; } @@ -101,7 +101,7 @@ void SetCacheStorageCacheName(const String& cache_storage_cache_name) { cache_storage_cache_name_ = cache_storage_cache_name; } - void SetCorsExposedHeaderNames(const HTTPHeaderSet& header_names) { + void SetCorsExposedHeaderNames(const WebCORS::HTTPHeaderSet& header_names) { cors_exposed_header_names_ = header_names; } @@ -132,7 +132,7 @@ String mime_type_; Time response_time_; String cache_storage_cache_name_; - HTTPHeaderSet cors_exposed_header_names_; + WebCORS::HTTPHeaderSet cors_exposed_header_names_; }; } // namespace blink
diff --git a/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp b/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp index e65f4ca..8d1bdeb 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchResponseDataTest.cpp
@@ -135,7 +135,7 @@ TEST_F(FetchResponseDataTest, CORSFilterWithEmptyHeaderSet) { FetchResponseData* internal_response = CreateInternalResponse(); FetchResponseData* cors_response_data = - internal_response->CreateCORSFilteredResponse(HTTPHeaderSet()); + internal_response->CreateCORSFilteredResponse(WebCORS::HTTPHeaderSet()); EXPECT_EQ(internal_response, cors_response_data->InternalResponse()); @@ -157,7 +157,7 @@ "set-cookie, bar"); FetchResponseData* cors_response_data = - internal_response->CreateCORSFilteredResponse(HTTPHeaderSet()); + internal_response->CreateCORSFilteredResponse(WebCORS::HTTPHeaderSet()); EXPECT_EQ(internal_response, cors_response_data->InternalResponse()); @@ -174,7 +174,7 @@ TEST_F(FetchResponseDataTest, CORSFilterWithExplicitHeaderSet) { FetchResponseData* internal_response = CreateInternalResponse(); - HTTPHeaderSet exposed_headers; + WebCORS::HTTPHeaderSet exposed_headers; exposed_headers.insert("set-cookie"); exposed_headers.insert("bar");
diff --git a/third_party/WebKit/Source/modules/fetch/Response.cpp b/third_party/WebKit/Source/modules/fetch/Response.cpp index 2fe272f5..84fc53f 100644 --- a/third_party/WebKit/Source/modules/fetch/Response.cpp +++ b/third_party/WebKit/Source/modules/fetch/Response.cpp
@@ -25,6 +25,7 @@ #include "modules/fetch/BodyStreamBuffer.h" #include "modules/fetch/FormDataBytesConsumer.h" #include "modules/fetch/ResponseInit.h" +#include "platform/HTTPNames.h" #include "platform/bindings/ScriptState.h" #include "platform/bindings/V8PrivateProperty.h" #include "platform/loader/fetch/FetchUtils.h" @@ -32,6 +33,7 @@ #include "platform/network/HTTPHeaderMap.h" #include "platform/network/NetworkUtils.h" #include "platform/wtf/RefPtr.h" +#include "public/platform/WebCORS.h" #include "public/platform/modules/serviceworker/WebServiceWorkerResponse.h" namespace blink { @@ -73,7 +75,7 @@ response = response->CreateBasicFilteredResponse(); break; case mojom::FetchResponseType::kCORS: { - HTTPHeaderSet header_names; + WebCORS::HTTPHeaderSet header_names; for (const auto& header : web_response.CorsExposedHeaderNames()) header_names.insert(String(header)); response = response->CreateCORSFilteredResponse(header_names);
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp index 3c4a4deb..a3e96e3 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ForeignFetchRespondWithObserver.cpp
@@ -7,7 +7,7 @@ #include "bindings/modules/v8/V8ForeignFetchResponse.h" #include "modules/fetch/Response.h" #include "modules/serviceworkers/ForeignFetchResponse.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" +#include "public/platform/WebCORS.h" namespace blink { @@ -68,16 +68,16 @@ kWebServiceWorkerResponseErrorForeignFetchMismatchedOrigin); return; } else if (!is_opaque) { - HTTPHeaderSet headers; + WebCORS::HTTPHeaderSet headers; if (foreign_fetch_response.hasHeaders()) { for (const String& header : foreign_fetch_response.headers()) headers.insert(header); if (response->GetResponse()->GetType() == FetchResponseData::kCORSType) { - const HTTPHeaderSet& existing_headers = + const WebCORS::HTTPHeaderSet& existing_headers = response->GetResponse()->CorsExposedHeaderNames(); - HTTPHeaderSet headers_to_remove; - for (HTTPHeaderSet::iterator it = headers.begin(); it != headers.end(); - ++it) { + WebCORS::HTTPHeaderSet headers_to_remove; + for (WebCORS::HTTPHeaderSet::iterator it = headers.begin(); + it != headers.end(); ++it) { if (!existing_headers.Contains(*it)) headers_to_remove.insert(*it); }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index 58d43cb..b44915a5 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -565,6 +565,7 @@ "exported/WebAudioBus.cpp", "exported/WebAudioDevice.cpp", "exported/WebBlobData.cpp", + "exported/WebCORS.cpp", "exported/WebCache.cpp", "exported/WebCanvasCaptureHandler.cpp", "exported/WebCoalescedInputEvent.cpp", @@ -1743,6 +1744,7 @@ "blob/BlobBytesProviderTest.cpp", "blob/BlobDataTest.cpp", "exported/FilePathConversionTest.cpp", + "exported/WebCORSTest.cpp", "exported/WebStringTest.cpp", "feature_policy/FeaturePolicyTest.cpp", "fonts/AcceptLanguagesResolverTest.cpp", @@ -2140,6 +2142,7 @@ "graphics/ImageLayerChromiumTest.cpp", "graphics/gpu/DrawingBufferSoftwareRenderingTest.cpp", "graphics/test/FakeGLES2Interface.h", + "graphics/test/FakeScrollableArea.h", "graphics/test/FakeWebGraphicsContext3DProvider.h", "graphics/test/MockImageDecoder.h", "graphics/test/MockPaintCanvas.h",
diff --git a/third_party/WebKit/Source/platform/DEPS b/third_party/WebKit/Source/platform/DEPS index e935b5e5..02ad5d36 100644 --- a/third_party/WebKit/Source/platform/DEPS +++ b/third_party/WebKit/Source/platform/DEPS
@@ -33,6 +33,7 @@ "+base/timer", "+base/trace_event", "+base/values.h", + "+net/http/http_util.h", "+device", "+gpu/GLES2", "+mojo/public",
diff --git a/third_party/WebKit/Source/platform/exported/WebCORS.cpp b/third_party/WebKit/Source/platform/exported/WebCORS.cpp new file mode 100644 index 0000000..d7c0cf1a --- /dev/null +++ b/third_party/WebKit/Source/platform/exported/WebCORS.cpp
@@ -0,0 +1,566 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "public/platform/WebCORS.h" + +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" +#include "net/http/http_util.h" +#include "platform/HTTPNames.h" +#include "platform/loader/fetch/FetchUtils.h" +#include "platform/loader/fetch/ResourceRequest.h" +#include "platform/network/HTTPHeaderMap.h" +#include "platform/weborigin/KURL.h" +#include "platform/weborigin/SchemeRegistry.h" +#include "platform/wtf/text/StringBuilder.h" +#include "platform/wtf/text/WTFString.h" +#include "public/platform/WebSecurityOrigin.h" +#include "public/platform/WebURLResponse.h" +#include "url/gurl.h" + +namespace blink { + +namespace WebCORS { + +namespace { + +bool IsInterestingStatusCode(int status_code) { + // Predicate that gates what status codes should be included in console error + // messages for responses containing no access control headers. + return status_code >= 400; +} + +// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0 +String CreateAccessControlRequestHeadersHeader(const HTTPHeaderMap& headers) { + Vector<String> filtered_headers; + for (const auto& header : headers) { + if (FetchUtils::IsCORSSafelistedHeader(header.key, header.value)) { + // Exclude CORS-safelisted headers. + continue; + } + // TODO(hintzed) replace with EqualIgnoringASCIICase() + if (DeprecatedEqualIgnoringCase(header.key, "referer")) { + // When the request is from a Worker, referrer header was added by + // WorkerThreadableLoader. But it should not be added to + // Access-Control-Request-Headers header. + continue; + } + filtered_headers.push_back(header.key.DeprecatedLower()); + } + if (!filtered_headers.size()) + return g_null_atom; + + // Sort header names lexicographically. + std::sort(filtered_headers.begin(), filtered_headers.end(), + WTF::CodePointCompareLessThan); + StringBuilder header_buffer; + for (const String& header : filtered_headers) { + if (!header_buffer.IsEmpty()) + header_buffer.Append(","); + header_buffer.Append(header); + } + + return header_buffer.ToString(); +} + +// A parser for the value of the Access-Control-Expose-Headers header. +class HTTPHeaderNameListParser { + STACK_ALLOCATED(); + + public: + explicit HTTPHeaderNameListParser(const String& value) + : value_(value), pos_(0) {} + + // Tries parsing |value_| expecting it to be conforming to the #field-name + // ABNF rule defined in RFC 7230. Returns with the field-name entries stored + // in |output| when successful. Otherwise, returns with |output| kept empty. + // + // |output| must be empty. + void Parse(HTTPHeaderSet& output) { + DCHECK(output.IsEmpty()); + + while (true) { + ConsumeSpaces(); + + size_t token_start = pos_; + ConsumeTokenChars(); + size_t token_size = pos_ - token_start; + if (token_size == 0) { + output.clear(); + return; + } + output.insert(value_.Substring(token_start, token_size)); + + ConsumeSpaces(); + + if (pos_ == value_.length()) { + return; + } + + if (value_[pos_] == ',') { + ++pos_; + } else { + output.clear(); + return; + } + } + } + + private: + // Consumes zero or more spaces (SP and HTAB) from value_. + void ConsumeSpaces() { + while (true) { + if (pos_ == value_.length()) { + return; + } + + UChar c = value_[pos_]; + if (c != ' ' && c != '\t') { + return; + } + ++pos_; + } + } + + // Consumes zero or more tchars from value_. + void ConsumeTokenChars() { + while (true) { + if (pos_ == value_.length()) { + return; + } + + UChar c = value_[pos_]; + if (c > 0x7F || !net::HttpUtil::IsTokenChar(c)) { + return; + } + ++pos_; + } + } + + const String value_; + size_t pos_; +}; + +static bool IsOriginSeparator(UChar ch) { + return IsASCIISpace(ch) || ch == ','; +} + +} // namespace + +AccessStatus CheckAccess( + const WebURLResponse& response, + const WebURLRequest::FetchCredentialsMode credentials_mode, + const WebSecurityOrigin& security_origin) { + int status_code = response.HttpStatusCode(); + if (!status_code) + return AccessStatus::kInvalidResponse; + + const WebString& allow_origin_header_value = + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Origin); + + // Check Suborigins, unless the Access-Control-Allow-Origin is '*', which + // implies that all Suborigins are okay as well. + if (!security_origin.Suborigin().IsEmpty() && + allow_origin_header_value != WebString(g_star_atom)) { + const WebString& allow_suborigin_header_value = + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Suborigin); + if (allow_suborigin_header_value != WebString(g_star_atom) && + allow_suborigin_header_value != security_origin.Suborigin()) { + return AccessStatus::kSubOriginMismatch; + } + } + + if (allow_origin_header_value == "*") { + // A wildcard Access-Control-Allow-Origin can not be used if credentials are + // to be sent, even with Access-Control-Allow-Credentials set to true. + if (!FetchUtils::ShouldTreatCredentialsModeAsInclude(credentials_mode)) + return AccessStatus::kAccessAllowed; + // TODO(hintzed): Is the following a sound substitute for + // blink::ResourceResponse::IsHTTP()? + if (GURL(response.Url().GetString().Utf16()).SchemeIsHTTPOrHTTPS()) { + return AccessStatus::kWildcardOriginNotAllowed; + } + } else if (allow_origin_header_value != security_origin.ToString()) { + if (allow_origin_header_value.IsNull()) + return AccessStatus::kMissingAllowOriginHeader; + if (String(allow_origin_header_value).Find(IsOriginSeparator, 0) != + kNotFound) { + return AccessStatus::kMultipleAllowOriginValues; + } + KURL header_origin(NullURL(), allow_origin_header_value); + if (!header_origin.IsValid()) + return AccessStatus::kInvalidAllowOriginValue; + + return AccessStatus::kAllowOriginMismatch; + } + + if (FetchUtils::ShouldTreatCredentialsModeAsInclude(credentials_mode)) { + const WebString& allow_credentials_header_value = + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Credentials); + if (allow_credentials_header_value != "true") { + return AccessStatus::kDisallowCredentialsNotSetToTrue; + } + } + return AccessStatus::kAccessAllowed; +} + +bool HandleRedirect(WebSecurityOrigin& current_security_origin, + WebURLRequest& new_request, + const WebURLResponse& redirect_response, + WebURLRequest::FetchCredentialsMode credentials_mode, + ResourceLoaderOptions& options, + WebString& error_message) { + const KURL& last_url = redirect_response.Url(); + const KURL& new_url = new_request.Url(); + + WebSecurityOrigin& new_security_origin = current_security_origin; + + // TODO(tyoshino): This should be fixed to check not only the last one but + // all redirect responses. + if (!current_security_origin.CanRequest(last_url)) { + RedirectStatus redirect_status = CheckRedirectLocation(new_url); + if (redirect_status != RedirectStatus::kRedirectSuccess) { + StringBuilder builder; + builder.Append("Redirect from '"); + builder.Append(last_url.GetString()); + builder.Append("' has been blocked by CORS policy: "); + builder.Append(RedirectErrorString(redirect_status, new_url)); + error_message = builder.ToString(); + return false; + } + + AccessStatus cors_status = CheckAccess(redirect_response, credentials_mode, + current_security_origin); + if (cors_status != AccessStatus::kAccessAllowed) { + StringBuilder builder; + builder.Append("Redirect from '"); + builder.Append(last_url.GetString()); + builder.Append("' has been blocked by CORS policy: "); + builder.Append(AccessControlErrorString( + cors_status, redirect_response, + WebSecurityOrigin(current_security_origin.Get()), + new_request.GetRequestContext())); + error_message = builder.ToString(); + return false; + } + + RefPtr<SecurityOrigin> last_origin = SecurityOrigin::Create(last_url); + // Set request's origin to a globally unique identifier as specified in + // the step 10 in https://fetch.spec.whatwg.org/#http-redirect-fetch. + if (!last_origin->CanRequest(new_url)) { + options.security_origin = SecurityOrigin::CreateUnique(); + new_security_origin = options.security_origin; + } + } + + if (!current_security_origin.CanRequest(new_url)) { + new_request.ClearHTTPHeaderField(WebString(HTTPNames::Suborigin)); + new_request.SetHTTPHeaderField(WebString(HTTPNames::Origin), + new_security_origin.ToString()); + if (!new_security_origin.Suborigin().IsEmpty()) { + new_request.SetHTTPHeaderField(WebString(HTTPNames::Suborigin), + new_security_origin.Suborigin()); + } + + options.cors_flag = true; + } + return true; +} + +RedirectStatus CheckRedirectLocation(const WebURL& web_request_url) { + // Block non HTTP(S) schemes as specified in the step 4 in + // https://fetch.spec.whatwg.org/#http-redirect-fetch. Chromium also allows + // the data scheme. + // + // TODO(tyoshino): This check should be performed regardless of the CORS flag + // and request's mode. + KURL request_url = web_request_url; + + if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled( + request_url.Protocol())) + return RedirectStatus::kRedirectDisallowedScheme; + + // Block URLs including credentials as specified in the step 9 in + // https://fetch.spec.whatwg.org/#http-redirect-fetch. + // + // TODO(tyoshino): This check should be performed also when request's + // origin is not same origin with the redirect destination's origin. + if (!(request_url.User().IsEmpty() && request_url.Pass().IsEmpty())) + return RedirectStatus::kRedirectContainsCredentials; + + return RedirectStatus::kRedirectSuccess; +} + +PreflightStatus CheckPreflight(const WebURLResponse& response) { + // CORS preflight with 3XX is considered network error in + // Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch + // CORS Spec: http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0 + // https://crbug.com/452394 + int status_code = response.HttpStatusCode(); + if (!FetchUtils::IsOkStatus(status_code)) + return PreflightStatus::kPreflightInvalidStatus; + + return PreflightStatus::kPreflightSuccess; +} + +PreflightStatus CheckExternalPreflight(const WebURLResponse& response) { + WebString result = + response.HttpHeaderField(HTTPNames::Access_Control_Allow_External); + if (result.IsNull()) + return PreflightStatus::kPreflightMissingAllowExternal; + // TODO(hintzed) replace with EqualIgnoringASCIICase() + if (!DeprecatedEqualIgnoringCase(result, "true")) + return PreflightStatus::kPreflightInvalidAllowExternal; + return PreflightStatus::kPreflightSuccess; +} + +WebURLRequest CreateAccessControlPreflightRequest( + const WebURLRequest& request) { + const KURL& request_url = request.Url(); + + DCHECK(request_url.User().IsEmpty()); + DCHECK(request_url.Pass().IsEmpty()); + + WebURLRequest preflight_request(request_url); + preflight_request.SetHTTPMethod(HTTPNames::OPTIONS); + preflight_request.SetHTTPHeaderField(HTTPNames::Access_Control_Request_Method, + request.HttpMethod()); + preflight_request.SetPriority(request.GetPriority()); + preflight_request.SetRequestContext(request.GetRequestContext()); + preflight_request.SetFetchCredentialsMode( + WebURLRequest::kFetchCredentialsModeOmit); + preflight_request.SetServiceWorkerMode( + WebURLRequest::ServiceWorkerMode::kNone); + + if (request.IsExternalRequest()) { + preflight_request.SetHTTPHeaderField( + HTTPNames::Access_Control_Request_External, "true"); + } + + String request_headers = CreateAccessControlRequestHeadersHeader( + request.ToResourceRequest().HttpHeaderFields()); + if (request_headers != g_null_atom) { + preflight_request.SetHTTPHeaderField( + HTTPNames::Access_Control_Request_Headers, request_headers); + } + + return preflight_request; +} + +WebString AccessControlErrorString( + const AccessStatus status, + const WebURLResponse& response, + const WebSecurityOrigin& origin, + const WebURLRequest::RequestContext context) { + String origin_denied = + String::Format("Origin '%s' is therefore not allowed access.", + origin.ToString().Utf8().data()); + + String no_cors_information = + context == WebURLRequest::kRequestContextFetch + ? " Have the server send the header with a valid value, or, if an " + "opaque response serves your needs, set the request's mode to " + "'no-cors' to fetch the resource with CORS disabled." + : ""; + + switch (status) { + case AccessStatus::kInvalidResponse: { + return String::Format("Invalid response. %s", + origin_denied.Utf8().data()); + } + case AccessStatus::kSubOriginMismatch: { + return String::Format( + "The 'Access-Control-Allow-Suborigin' header has a value '%s' that " + "is not equal to the supplied suborigin. %s", + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Suborigin) + .Utf8() + .data(), + origin_denied.Utf8().data()); + } + case AccessStatus::kWildcardOriginNotAllowed: { + return String::Format( + "The value of the 'Access-Control-Allow-Origin' header in the " + "response must not be the wildcard '*' when the request's " + "credentials mode is 'include'. %s%s", + origin_denied.Utf8().data(), + context == WebURLRequest::kRequestContextXMLHttpRequest + ? " The credentials mode of requests initiated by the " + "XMLHttpRequest is controlled by the withCredentials attribute." + : ""); + } + case AccessStatus::kMissingAllowOriginHeader: { + String status_code_msg = + IsInterestingStatusCode(response.HttpStatusCode()) + ? String::Format(" The response had HTTP status code %d.", + response.HttpStatusCode()) + : ""; + + return String::Format( + "No 'Access-Control-Allow-Origin' header is present on the " + "requested resource. %s%s%s", + origin_denied.Utf8().data(), status_code_msg.Utf8().data(), + context == WebURLRequest::kRequestContextFetch + ? " If an opaque response serves your needs, set the request's " + "mode to 'no-cors' to fetch the resource with CORS disabled." + : ""); + } + case AccessStatus::kMultipleAllowOriginValues: { + return String::Format( + "The 'Access-Control-Allow-Origin' header contains multiple values " + "'%s', but only one is allowed. %s%s", + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Origin) + .Utf8() + .data(), + origin_denied.Utf8().data(), no_cors_information.Utf8().data()); + } + case AccessStatus::kInvalidAllowOriginValue: { + return String::Format( + "The 'Access-Control-Allow-Origin' header contains the invalid value " + "'%s'. %s%s", + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Origin) + .Utf8() + .data(), + origin_denied.Utf8().data(), no_cors_information.Utf8().data()); + } + case AccessStatus::kAllowOriginMismatch: { + return String::Format( + "The 'Access-Control-Allow-Origin' header has a value '%s' that is " + "not equal to the supplied origin. %s%s", + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Origin) + .Utf8() + .data(), + origin_denied.Utf8().data(), no_cors_information.Utf8().data()); + } + case AccessStatus::kDisallowCredentialsNotSetToTrue: { + return String::Format( + "The value of the 'Access-Control-Allow-Credentials' header in " + "the response is '%s' which must be 'true' when the request's " + "credentials mode is 'include'. %s%s", + response.HttpHeaderField(HTTPNames::Access_Control_Allow_Credentials) + .Utf8() + .data(), + origin_denied.Utf8().data(), + (context == WebURLRequest::kRequestContextXMLHttpRequest + ? " The credentials mode of requests initiated by the " + "XMLHttpRequest is controlled by the withCredentials " + "attribute." + : "")); + } + default: + NOTREACHED(); + return ""; + } +} + +WebString PreflightErrorString(PreflightStatus status, + const WebURLResponse& response) { + switch (status) { + case PreflightStatus::kPreflightInvalidStatus: { + return String::Format( + "Response for preflight has invalid HTTP status code %d", + response.HttpStatusCode()); + } + case PreflightStatus::kPreflightMissingAllowExternal: { + return String::Format( + "No 'Access-Control-Allow-External' header was present in the " + "preflight response for this external request (This is an " + "experimental header which is defined in " + "'https://wicg.github.io/cors-rfc1918/')."); + } + case PreflightStatus::kPreflightInvalidAllowExternal: { + return String::Format( + "The 'Access-Control-Allow-External' header in the preflight " + "response for this external request had a value of '%s', not 'true' " + "(This is an experimental header which is defined in " + "'https://wicg.github.io/cors-rfc1918/').", + response.HttpHeaderField("access-control-allow-external") + .Utf8() + .data()); + } + default: + NOTREACHED(); + return ""; + } +} + +WebString RedirectErrorString(const RedirectStatus status, + const WebURL& redirect_url) { + switch (status) { + case kRedirectDisallowedScheme: { + return String::Format( + "Redirect location '%s' has a disallowed scheme for cross-origin " + "requests.", + redirect_url.GetString().Utf8().data()); + } + case kRedirectContainsCredentials: { + return String::Format( + "Redirect location '%s' contains a username and password, which is " + "disallowed for cross-origin requests.", + redirect_url.GetString().Utf8().data()); + } + default: + NOTREACHED(); + return ""; + } +} + +void ExtractCorsExposedHeaderNamesList(const WebURLResponse& response, + HTTPHeaderSet& header_set) { + // If a response was fetched via a service worker, it will always have + // CorsExposedHeaderNames set, either from the Access-Control-Expose-Headers + // header, or explicitly via foreign fetch. For requests that didn't come from + // a service worker, foreign fetch doesn't apply so just parse the CORS + // header. + if (response.WasFetchedViaServiceWorker()) { + for (const auto& header : response.CorsExposedHeaderNames()) + header_set.insert(String(header)); + return; + } + ParseAccessControlExposeHeadersAllowList( + response.HttpHeaderField( + WebString(HTTPNames::Access_Control_Expose_Headers)), + header_set); +} + +void ParseAccessControlExposeHeadersAllowList(const WebString& header_value, + HTTPHeaderSet& header_set) { + HTTPHeaderNameListParser parser(header_value); + parser.Parse(header_set); +} + +bool IsOnAccessControlResponseHeaderWhitelist(const WebString& name) { + DEFINE_THREAD_SAFE_STATIC_LOCAL( + HTTPHeaderSet, allowed_cross_origin_response_headers, + ({ + "cache-control", "content-language", "content-type", "expires", + "last-modified", "pragma", + })); + return allowed_cross_origin_response_headers.Contains(name); +} + +} // namespace WebCORS + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebCORSTest.cpp b/third_party/WebKit/Source/platform/exported/WebCORSTest.cpp new file mode 100644 index 0000000..d14118d --- /dev/null +++ b/third_party/WebKit/Source/platform/exported/WebCORSTest.cpp
@@ -0,0 +1,167 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "public/platform/WebCORS.h" + +#include "platform/loader/fetch/ResourceRequest.h" +#include "platform/weborigin/SecurityOrigin.h" +#include "platform/wtf/RefPtr.h" +#include "platform/wtf/text/WTFString.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +namespace { + +TEST(CreateAccessControlPreflightRequestTest, LexicographicalOrder) { + WebURLRequest request; + request.AddHTTPHeaderField("Orange", "Orange"); + request.AddHTTPHeaderField("Apple", "Red"); + request.AddHTTPHeaderField("Kiwifruit", "Green"); + request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); + request.AddHTTPHeaderField("Strawberry", "Red"); + + WebURLRequest preflight = + WebCORS::CreateAccessControlPreflightRequest(request); + + EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry", + preflight.HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(CreateAccessControlPreflightRequestTest, ExcludeSimpleHeaders) { + WebURLRequest request; + request.AddHTTPHeaderField("Accept", "everything"); + request.AddHTTPHeaderField("Accept-Language", "everything"); + request.AddHTTPHeaderField("Content-Language", "everything"); + request.AddHTTPHeaderField("Save-Data", "on"); + + WebURLRequest preflight = + WebCORS::CreateAccessControlPreflightRequest(request); + + // Do not emit empty-valued headers; an empty list of non-"CORS safelisted" + // request headers should cause "Access-Control-Request-Headers:" to be + // left out in the preflight request. + EXPECT_EQ(WebString(g_null_atom), + preflight.HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(CreateAccessControlPreflightRequestTest, ExcludeSimpleContentTypeHeader) { + WebURLRequest request; + request.AddHTTPHeaderField("Content-Type", "text/plain"); + + WebURLRequest preflight = + WebCORS::CreateAccessControlPreflightRequest(request); + + // Empty list also; see comment in test above. + EXPECT_EQ(WebString(g_null_atom), + preflight.HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(CreateAccessControlPreflightRequestTest, IncludeNonSimpleHeader) { + WebURLRequest request; + request.AddHTTPHeaderField("X-Custom-Header", "foobar"); + + WebURLRequest preflight = + WebCORS::CreateAccessControlPreflightRequest(request); + + EXPECT_EQ("x-custom-header", + preflight.HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(CreateAccessControlPreflightRequestTest, + IncludeNonSimpleContentTypeHeader) { + WebURLRequest request; + request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); + + WebURLRequest preflight = + WebCORS::CreateAccessControlPreflightRequest(request); + + EXPECT_EQ("content-type", + preflight.HttpHeaderField("Access-Control-Request-Headers")); +} + +TEST(ParseAccessControlExposeHeadersAllowListTest, ValidInput) { + WebCORS::HTTPHeaderSet set; + WebCORS::ParseAccessControlExposeHeadersAllowList("valid", set); + EXPECT_EQ(1U, set.size()); + EXPECT_TRUE(set.Contains("valid")); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList("a,b", set); + EXPECT_EQ(2U, set.size()); + EXPECT_TRUE(set.Contains("a")); + EXPECT_TRUE(set.Contains("b")); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList(" a , b ", set); + EXPECT_EQ(2U, set.size()); + EXPECT_TRUE(set.Contains("a")); + EXPECT_TRUE(set.Contains("b")); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList(" \t \t\t a", set); + EXPECT_EQ(1U, set.size()); + EXPECT_TRUE(set.Contains("a")); +} + +TEST(ParseAccessControlExposeHeadersAllowListTest, DuplicatedEntries) { + WebCORS::HTTPHeaderSet set; + WebCORS::ParseAccessControlExposeHeadersAllowList("a, a", set); + EXPECT_EQ(1U, set.size()); + EXPECT_TRUE(set.Contains("a")); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList("a, a, b", set); + EXPECT_EQ(2U, set.size()); + EXPECT_TRUE(set.Contains("a")); + EXPECT_TRUE(set.Contains("b")); +} + +TEST(ParseAccessControlExposeHeadersAllowListTest, InvalidInput) { + WebCORS::HTTPHeaderSet set; + WebCORS::ParseAccessControlExposeHeadersAllowList("not valid", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList("///", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList("/a/", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList(",", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList(" , ", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList(" , a", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList("a , ", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList("", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + WebCORS::ParseAccessControlExposeHeadersAllowList(" ", set); + EXPECT_TRUE(set.IsEmpty()); + + set.clear(); + // U+0141 which is 'A' (0x41) + 0x100. + WebCORS::ParseAccessControlExposeHeadersAllowList( + String::FromUTF8("\xC5\x81"), set); + EXPECT_TRUE(set.IsEmpty()); +} + +} // namespace + +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp index 7558c19..b37e16c 100644 --- a/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp +++ b/third_party/WebKit/Source/platform/exported/WebURLResponse.cpp
@@ -317,6 +317,10 @@ resource_response_->SetCacheStorageCacheName(cache_storage_cache_name); } +WebVector<WebString> WebURLResponse::CorsExposedHeaderNames() const { + return resource_response_->CorsExposedHeaderNames(); +} + void WebURLResponse::SetCorsExposedHeaderNames( const WebVector<WebString>& header_names) { Vector<String> exposed_header_names;
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp index ace06512..db0a8214 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
@@ -35,6 +35,7 @@ #include "platform/animation/CompositorFloatAnimationCurve.h" #include "platform/animation/CompositorTargetProperty.h" #include "platform/graphics/CompositorElementId.h" +#include "platform/graphics/test/FakeScrollableArea.h" #include "platform/scheduler/child/web_scheduler.h" #include "platform/scroll/ScrollableArea.h" #include "platform/testing/FakeGraphicsLayer.h" @@ -166,53 +167,4 @@ host.RemoveTimeline(*compositor_timeline.get()); } -class FakeScrollableArea : public GarbageCollectedFinalized<FakeScrollableArea>, - public ScrollableArea { - USING_GARBAGE_COLLECTED_MIXIN(FakeScrollableArea); - - public: - static FakeScrollableArea* Create() { return new FakeScrollableArea; } - - CompositorElementId GetCompositorElementId() const override { - return CompositorElementId(); - } - bool IsActive() const override { return false; } - int ScrollSize(ScrollbarOrientation) const override { return 100; } - bool IsScrollCornerVisible() const override { return false; } - IntRect ScrollCornerRect() const override { return IntRect(); } - IntRect VisibleContentRect( - IncludeScrollbarsInRect = kExcludeScrollbars) const override { - return IntRect(ScrollOffsetInt().Width(), ScrollOffsetInt().Height(), 10, - 10); - } - IntSize ContentsSize() const override { return IntSize(100, 100); } - bool ScrollbarsCanBeActive() const override { return false; } - IntRect ScrollableAreaBoundingBox() const override { return IntRect(); } - void ScrollControlWasSetNeedsPaintInvalidation() override {} - bool UserInputScrollable(ScrollbarOrientation) const override { return true; } - bool ShouldPlaceVerticalScrollbarOnLeft() const override { return false; } - int PageStep(ScrollbarOrientation) const override { return 0; } - IntSize MinimumScrollOffsetInt() const override { return IntSize(); } - IntSize MaximumScrollOffsetInt() const override { - return ContentsSize() - IntSize(VisibleWidth(), VisibleHeight()); - } - - void UpdateScrollOffset(const ScrollOffset& offset, ScrollType) override { - scroll_offset_ = offset; - } - ScrollOffset GetScrollOffset() const override { return scroll_offset_; } - IntSize ScrollOffsetInt() const override { - return FlooredIntSize(scroll_offset_); - } - - RefPtr<WebTaskRunner> GetTimerTaskRunner() const final { - return Platform::Current()->CurrentThread()->Scheduler()->TimerTaskRunner(); - } - - DEFINE_INLINE_VIRTUAL_TRACE() { ScrollableArea::Trace(visitor); } - - private: - ScrollOffset scroll_offset_; -}; - } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/test/FakeScrollableArea.h b/third_party/WebKit/Source/platform/graphics/test/FakeScrollableArea.h new file mode 100644 index 0000000..cf0a285d --- /dev/null +++ b/third_party/WebKit/Source/platform/graphics/test/FakeScrollableArea.h
@@ -0,0 +1,65 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FakeScrollableArea_h +#define FakeScrollableArea_h + +#include "platform/scheduler/child/web_scheduler.h" +#include "platform/scroll/ScrollableArea.h" +#include "public/platform/Platform.h" + +namespace blink { + +class FakeScrollableArea : public GarbageCollectedFinalized<FakeScrollableArea>, + public ScrollableArea { + USING_GARBAGE_COLLECTED_MIXIN(FakeScrollableArea); + + public: + static FakeScrollableArea* Create() { return new FakeScrollableArea; } + + CompositorElementId GetCompositorElementId() const override { + return CompositorElementId(); + } + bool IsActive() const override { return false; } + int ScrollSize(ScrollbarOrientation) const override { return 100; } + bool IsScrollCornerVisible() const override { return false; } + IntRect ScrollCornerRect() const override { return IntRect(); } + IntRect VisibleContentRect( + IncludeScrollbarsInRect = kExcludeScrollbars) const override { + return IntRect(ScrollOffsetInt().Width(), ScrollOffsetInt().Height(), 10, + 10); + } + IntSize ContentsSize() const override { return IntSize(100, 100); } + bool ScrollbarsCanBeActive() const override { return false; } + IntRect ScrollableAreaBoundingBox() const override { return IntRect(); } + void ScrollControlWasSetNeedsPaintInvalidation() override {} + bool UserInputScrollable(ScrollbarOrientation) const override { return true; } + bool ShouldPlaceVerticalScrollbarOnLeft() const override { return false; } + int PageStep(ScrollbarOrientation) const override { return 0; } + IntSize MinimumScrollOffsetInt() const override { return IntSize(); } + IntSize MaximumScrollOffsetInt() const override { + return ContentsSize() - IntSize(VisibleWidth(), VisibleHeight()); + } + + void UpdateScrollOffset(const ScrollOffset& offset, ScrollType) override { + scroll_offset_ = offset; + } + ScrollOffset GetScrollOffset() const override { return scroll_offset_; } + IntSize ScrollOffsetInt() const override { + return FlooredIntSize(scroll_offset_); + } + + RefPtr<WebTaskRunner> GetTimerTaskRunner() const final { + return Platform::Current()->CurrentThread()->Scheduler()->TimerTaskRunner(); + } + + DEFINE_INLINE_VIRTUAL_TRACE() { ScrollableArea::Trace(visitor); } + + private: + ScrollOffset scroll_offset_; +}; + +} // namespace blink + +#endif // FakeScrollableArea
diff --git a/third_party/WebKit/Source/platform/loader/BUILD.gn b/third_party/WebKit/Source/platform/loader/BUILD.gn index 409befe..492cd20 100644 --- a/third_party/WebKit/Source/platform/loader/BUILD.gn +++ b/third_party/WebKit/Source/platform/loader/BUILD.gn
@@ -31,8 +31,6 @@ "fetch/CachedMetadataHandler.h", "fetch/ClientHintsPreferences.cpp", "fetch/ClientHintsPreferences.h", - "fetch/CrossOriginAccessControl.cpp", - "fetch/CrossOriginAccessControl.h", "fetch/FetchContext.cpp", "fetch/FetchContext.h", "fetch/FetchInitiatorInfo.h", @@ -123,7 +121,6 @@ "SubresourceIntegrityTest.cpp", "fetch/BufferingDataPipeWriterTest.cpp", "fetch/ClientHintsPreferencesTest.cpp", - "fetch/CrossOriginAccessControlTest.cpp", "fetch/FetchUtilsTest.cpp", "fetch/MemoryCacheCorrectnessTest.cpp", "fetch/MemoryCacheTest.cpp",
diff --git a/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControl.cpp b/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControl.cpp deleted file mode 100644 index 8a1246b..0000000 --- a/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControl.cpp +++ /dev/null
@@ -1,607 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#include "platform/loader/fetch/CrossOriginAccessControl.h" - -#include <algorithm> -#include <memory> -#include "net/http/http_util.h" -#include "platform/loader/fetch/FetchUtils.h" -#include "platform/loader/fetch/Resource.h" -#include "platform/loader/fetch/ResourceLoaderOptions.h" -#include "platform/loader/fetch/ResourceRequest.h" -#include "platform/loader/fetch/ResourceResponse.h" -#include "platform/network/HTTPParsers.h" -#include "platform/weborigin/SchemeRegistry.h" -#include "platform/weborigin/SecurityOrigin.h" -#include "platform/wtf/PtrUtil.h" -#include "platform/wtf/Threading.h" -#include "platform/wtf/text/AtomicString.h" -#include "platform/wtf/text/StringBuilder.h" - -namespace blink { - -bool CrossOriginAccessControl::IsOnAccessControlResponseHeaderWhitelist( - const String& name) { - DEFINE_THREAD_SAFE_STATIC_LOCAL( - HTTPHeaderSet, allowed_cross_origin_response_headers, - ({ - "cache-control", "content-language", "content-type", "expires", - "last-modified", "pragma", - })); - return allowed_cross_origin_response_headers.Contains(name); -} - -// Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0 -static AtomicString CreateAccessControlRequestHeadersHeader( - const HTTPHeaderMap& headers) { - Vector<String> filtered_headers; - for (const auto& header : headers) { - if (FetchUtils::IsCORSSafelistedHeader(header.key, header.value)) { - // Exclude CORS-safelisted headers. - continue; - } - if (DeprecatedEqualIgnoringCase(header.key, "referer")) { - // When the request is from a Worker, referrer header was added by - // WorkerThreadableLoader. But it should not be added to - // Access-Control-Request-Headers header. - continue; - } - filtered_headers.push_back(header.key.DeprecatedLower()); - } - if (!filtered_headers.size()) - return g_null_atom; - - // Sort header names lexicographically. - std::sort(filtered_headers.begin(), filtered_headers.end(), - WTF::CodePointCompareLessThan); - StringBuilder header_buffer; - for (const String& header : filtered_headers) { - if (!header_buffer.IsEmpty()) - header_buffer.Append(","); - header_buffer.Append(header); - } - - return AtomicString(header_buffer.ToString()); -} - -ResourceRequest CrossOriginAccessControl::CreateAccessControlPreflightRequest( - const ResourceRequest& request) { - const KURL& request_url = request.Url(); - - DCHECK(request_url.User().IsEmpty()); - DCHECK(request_url.Pass().IsEmpty()); - - ResourceRequest preflight_request(request_url); - preflight_request.SetHTTPMethod(HTTPNames::OPTIONS); - preflight_request.SetHTTPHeaderField(HTTPNames::Access_Control_Request_Method, - AtomicString(request.HttpMethod())); - preflight_request.SetPriority(request.Priority()); - preflight_request.SetRequestContext(request.GetRequestContext()); - preflight_request.SetFetchCredentialsMode( - WebURLRequest::kFetchCredentialsModeOmit); - preflight_request.SetServiceWorkerMode( - WebURLRequest::ServiceWorkerMode::kNone); - - if (request.IsExternalRequest()) { - preflight_request.SetHTTPHeaderField( - HTTPNames::Access_Control_Request_External, "true"); - } - - AtomicString request_headers = - CreateAccessControlRequestHeadersHeader(request.HttpHeaderFields()); - if (request_headers != g_null_atom) { - preflight_request.SetHTTPHeaderField( - HTTPNames::Access_Control_Request_Headers, request_headers); - } - - return preflight_request; -} - -static bool IsOriginSeparator(UChar ch) { - return IsASCIISpace(ch) || ch == ','; -} - -CrossOriginAccessControl::AccessStatus CrossOriginAccessControl::CheckAccess( - const ResourceResponse& response, - WebURLRequest::FetchCredentialsMode credentials_mode, - const SecurityOrigin* security_origin) { - static const char allow_origin_header_name[] = "access-control-allow-origin"; - static const char allow_credentials_header_name[] = - "access-control-allow-credentials"; - static const char allow_suborigin_header_name[] = - "access-control-allow-suborigin"; - int status_code = response.HttpStatusCode(); - if (!status_code) - return kInvalidResponse; - - const AtomicString& allow_origin_header_value = - response.HttpHeaderField(allow_origin_header_name); - - // Check Suborigins, unless the Access-Control-Allow-Origin is '*', which - // implies that all Suborigins are okay as well. - if (security_origin->HasSuborigin() && - allow_origin_header_value != g_star_atom) { - const AtomicString& allow_suborigin_header_value = - response.HttpHeaderField(allow_suborigin_header_name); - AtomicString atomic_suborigin_name( - security_origin->GetSuborigin()->GetName()); - if (allow_suborigin_header_value != g_star_atom && - allow_suborigin_header_value != atomic_suborigin_name) { - return kSubOriginMismatch; - } - } - - if (allow_origin_header_value == "*") { - // A wildcard Access-Control-Allow-Origin can not be used if credentials are - // to be sent, even with Access-Control-Allow-Credentials set to true. - if (!FetchUtils::ShouldTreatCredentialsModeAsInclude(credentials_mode)) - return kAccessAllowed; - if (response.IsHTTP()) { - return kWildcardOriginNotAllowed; - } - } else if (allow_origin_header_value != security_origin->ToAtomicString()) { - if (allow_origin_header_value.IsNull()) - return kMissingAllowOriginHeader; - if (allow_origin_header_value.GetString().Find(IsOriginSeparator, 0) != - kNotFound) { - return kMultipleAllowOriginValues; - } - KURL header_origin(NullURL(), allow_origin_header_value); - if (!header_origin.IsValid()) - return kInvalidAllowOriginValue; - - return kAllowOriginMismatch; - } - - if (FetchUtils::ShouldTreatCredentialsModeAsInclude(credentials_mode)) { - const AtomicString& allow_credentials_header_value = - response.HttpHeaderField(allow_credentials_header_name); - if (allow_credentials_header_value != "true") { - return kDisallowCredentialsNotSetToTrue; - } - } - return kAccessAllowed; -} - -static bool IsInterestingStatusCode(int status_code) { - // Predicate that gates what status codes should be included in console error - // messages for responses containing no access control headers. - return status_code >= 400; -} - -static void AppendOriginDeniedMessage(StringBuilder& builder, - const SecurityOrigin* security_origin) { - builder.Append(" Origin '"); - builder.Append(security_origin->ToString()); - builder.Append("' is therefore not allowed access."); -} - -static void AppendNoCORSInformationalMessage( - StringBuilder& builder, - WebURLRequest::RequestContext context) { - if (context != WebURLRequest::kRequestContextFetch) - return; - builder.Append( - " Have the server send the header with a valid value, or, if an " - "opaque response serves your needs, set the request's mode to " - "'no-cors' to fetch the resource with CORS disabled."); -} - -void CrossOriginAccessControl::AccessControlErrorString( - StringBuilder& builder, - CrossOriginAccessControl::AccessStatus status, - const ResourceResponse& response, - const SecurityOrigin* security_origin, - WebURLRequest::RequestContext context) { - DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, allow_origin_header_name, - ("access-control-allow-origin")); - DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, allow_credentials_header_name, - ("access-control-allow-credentials")); - DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, allow_suborigin_header_name, - ("access-control-allow-suborigin")); - - switch (status) { - case kInvalidResponse: { - builder.Append("Invalid response."); - AppendOriginDeniedMessage(builder, security_origin); - return; - } - case kSubOriginMismatch: { - const AtomicString& allow_suborigin_header_value = - response.HttpHeaderField(allow_suborigin_header_name); - builder.Append( - "The 'Access-Control-Allow-Suborigin' header has a value '"); - builder.Append(allow_suborigin_header_value); - builder.Append("' that is not equal to the supplied suborigin."); - AppendOriginDeniedMessage(builder, security_origin); - return; - } - case kWildcardOriginNotAllowed: { - builder.Append( - "The value of the 'Access-Control-Allow-Origin' header in the " - "response must not be the wildcard '*' when the request's " - "credentials mode is 'include'."); - AppendOriginDeniedMessage(builder, security_origin); - if (context == WebURLRequest::kRequestContextXMLHttpRequest) { - builder.Append( - " The credentials mode of requests initiated by the " - "XMLHttpRequest is controlled by the withCredentials attribute."); - } - return; - } - case kMissingAllowOriginHeader: { - builder.Append( - "No 'Access-Control-Allow-Origin' header is present on the requested " - "resource."); - AppendOriginDeniedMessage(builder, security_origin); - int status_code = response.HttpStatusCode(); - if (IsInterestingStatusCode(status_code)) { - builder.Append(" The response had HTTP status code "); - builder.Append(String::Number(status_code)); - builder.Append('.'); - } - if (context == WebURLRequest::kRequestContextFetch) { - builder.Append( - " If an opaque response serves your needs, set the request's mode " - "to 'no-cors' to fetch the resource with CORS disabled."); - } - return; - } - case kMultipleAllowOriginValues: { - const AtomicString& allow_origin_header_value = - response.HttpHeaderField(allow_origin_header_name); - builder.Append( - "The 'Access-Control-Allow-Origin' header contains multiple values " - "'"); - builder.Append(allow_origin_header_value); - builder.Append("', but only one is allowed."); - AppendOriginDeniedMessage(builder, security_origin); - AppendNoCORSInformationalMessage(builder, context); - return; - } - case kInvalidAllowOriginValue: { - const AtomicString& allow_origin_header_value = - response.HttpHeaderField(allow_origin_header_name); - builder.Append( - "The 'Access-Control-Allow-Origin' header contains the invalid " - "value '"); - builder.Append(allow_origin_header_value); - builder.Append("'."); - AppendOriginDeniedMessage(builder, security_origin); - AppendNoCORSInformationalMessage(builder, context); - return; - } - case kAllowOriginMismatch: { - const AtomicString& allow_origin_header_value = - response.HttpHeaderField(allow_origin_header_name); - builder.Append("The 'Access-Control-Allow-Origin' header has a value '"); - builder.Append(allow_origin_header_value); - builder.Append("' that is not equal to the supplied origin."); - AppendOriginDeniedMessage(builder, security_origin); - AppendNoCORSInformationalMessage(builder, context); - return; - } - case kDisallowCredentialsNotSetToTrue: { - const AtomicString& allow_credentials_header_value = - response.HttpHeaderField(allow_credentials_header_name); - builder.Append( - "The value of the 'Access-Control-Allow-Credentials' header in " - "the response is '"); - builder.Append(allow_credentials_header_value); - builder.Append( - "' which must " - "be 'true' when the request's credentials mode is 'include'."); - AppendOriginDeniedMessage(builder, security_origin); - if (context == WebURLRequest::kRequestContextXMLHttpRequest) { - builder.Append( - " The credentials mode of requests initiated by the " - "XMLHttpRequest is controlled by the withCredentials attribute."); - } - return; - } - default: - NOTREACHED(); - } -} - -CrossOriginAccessControl::PreflightStatus -CrossOriginAccessControl::CheckPreflight(const ResourceResponse& response) { - // CORS preflight with 3XX is considered network error in - // Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch - // CORS Spec: http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0 - // https://crbug.com/452394 - int status_code = response.HttpStatusCode(); - if (!FetchUtils::IsOkStatus(status_code)) - return kPreflightInvalidStatus; - - return kPreflightSuccess; -} - -CrossOriginAccessControl::PreflightStatus -CrossOriginAccessControl::CheckExternalPreflight( - const ResourceResponse& response) { - AtomicString result = - response.HttpHeaderField(HTTPNames::Access_Control_Allow_External); - if (result.IsNull()) - return kPreflightMissingAllowExternal; - if (!DeprecatedEqualIgnoringCase(result, "true")) - return kPreflightInvalidAllowExternal; - return kPreflightSuccess; -} - -void CrossOriginAccessControl::PreflightErrorString( - StringBuilder& builder, - CrossOriginAccessControl::PreflightStatus status, - const ResourceResponse& response) { - switch (status) { - case kPreflightInvalidStatus: { - int status_code = response.HttpStatusCode(); - builder.Append("Response for preflight has invalid HTTP status code "); - builder.Append(String::Number(status_code)); - return; - } - case kPreflightMissingAllowExternal: { - builder.Append( - "No 'Access-Control-Allow-External' header was present in "); - builder.Append( - "the preflight response for this external request (This is"); - builder.Append(" an experimental header which is defined in "); - builder.Append("'https://wicg.github.io/cors-rfc1918/')."); - return; - } - case kPreflightInvalidAllowExternal: { - String result = - response.HttpHeaderField(HTTPNames::Access_Control_Allow_External); - builder.Append("The 'Access-Control-Allow-External' header in the "); - builder.Append( - "preflight response for this external request had a value"); - builder.Append(" of '"); - builder.Append(result); - builder.Append("', not 'true' (This is an experimental header which is"); - builder.Append(" defined in 'https://wicg.github.io/cors-rfc1918/')."); - return; - } - default: - NOTREACHED(); - } -} - -// A parser for the value of the Access-Control-Expose-Headers header. -class HTTPHeaderNameListParser { - STACK_ALLOCATED(); - - public: - explicit HTTPHeaderNameListParser(const String& value) - : value_(value), pos_(0) {} - - // Tries parsing |value_| expecting it to be conforming to the #field-name - // ABNF rule defined in RFC 7230. Returns with the field-name entries stored - // in |output| when successful. Otherwise, returns with |output| kept empty. - // - // |output| must be empty. - void Parse(HTTPHeaderSet& output) { - DCHECK(output.IsEmpty()); - - while (true) { - ConsumeSpaces(); - - size_t token_start = pos_; - ConsumeTokenChars(); - size_t token_size = pos_ - token_start; - if (token_size == 0) { - output.clear(); - return; - } - output.insert(value_.Substring(token_start, token_size)); - - ConsumeSpaces(); - - if (pos_ == value_.length()) { - return; - } - - if (value_[pos_] == ',') { - ++pos_; - } else { - output.clear(); - return; - } - } - } - - private: - // Consumes zero or more spaces (SP and HTAB) from value_. - void ConsumeSpaces() { - while (true) { - if (pos_ == value_.length()) { - return; - } - - UChar c = value_[pos_]; - if (c != ' ' && c != '\t') { - return; - } - ++pos_; - } - } - - // Consumes zero or more tchars from value_. - void ConsumeTokenChars() { - while (true) { - if (pos_ == value_.length()) { - return; - } - - UChar c = value_[pos_]; - if (c > 0x7F || !net::HttpUtil::IsTokenChar(c)) { - return; - } - ++pos_; - } - } - - const String& value_; - size_t pos_; -}; - -void CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( - const String& header_value, - HTTPHeaderSet& header_set) { - HTTPHeaderNameListParser parser(header_value); - parser.Parse(header_set); -} - -void CrossOriginAccessControl::ExtractCorsExposedHeaderNamesList( - const ResourceResponse& response, - HTTPHeaderSet& header_set) { - // If a response was fetched via a service worker, it will always have - // corsExposedHeaderNames set, either from the Access-Control-Expose-Headers - // header, or explicitly via foreign fetch. For requests that didn't come from - // a service worker, foreign fetch doesn't apply so just parse the CORS - // header. - if (response.WasFetchedViaServiceWorker()) { - for (const auto& header : response.CorsExposedHeaderNames()) - header_set.insert(header); - return; - } - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( - response.HttpHeaderField(HTTPNames::Access_Control_Expose_Headers), - header_set); -} - -CrossOriginAccessControl::RedirectStatus -CrossOriginAccessControl::CheckRedirectLocation(const KURL& request_url) { - // Block non HTTP(S) schemes as specified in the step 4 in - // https://fetch.spec.whatwg.org/#http-redirect-fetch. Chromium also allows - // the data scheme. - // - // TODO(tyoshino): This check should be performed regardless of the CORS flag - // and request's mode. - if (!SchemeRegistry::ShouldTreatURLSchemeAsCORSEnabled( - request_url.Protocol())) - return kRedirectDisallowedScheme; - - // Block URLs including credentials as specified in the step 9 in - // https://fetch.spec.whatwg.org/#http-redirect-fetch. - // - // TODO(tyoshino): This check should be performed also when request's - // origin is not same origin with the redirect destination's origin. - if (!(request_url.User().IsEmpty() && request_url.Pass().IsEmpty())) - return kRedirectContainsCredentials; - - return kRedirectSuccess; -} - -void CrossOriginAccessControl::RedirectErrorString( - StringBuilder& builder, - CrossOriginAccessControl::RedirectStatus status, - const KURL& request_url) { - switch (status) { - case kRedirectDisallowedScheme: { - builder.Append("Redirect location '"); - builder.Append(request_url.GetString()); - builder.Append("' has a disallowed scheme for cross-origin requests."); - return; - } - case kRedirectContainsCredentials: { - builder.Append("Redirect location '"); - builder.Append(request_url.GetString()); - builder.Append( - "' contains a username and password, which is disallowed for" - " cross-origin requests."); - return; - } - default: - NOTREACHED(); - } -} - -bool CrossOriginAccessControl::HandleRedirect( - RefPtr<SecurityOrigin> current_security_origin, - ResourceRequest& new_request, - const ResourceResponse& redirect_response, - WebURLRequest::FetchCredentialsMode credentials_mode, - ResourceLoaderOptions& options, - String& error_message) { - // http://www.w3.org/TR/cors/#redirect-steps terminology: - const KURL& last_url = redirect_response.Url(); - const KURL& new_url = new_request.Url(); - - RefPtr<SecurityOrigin> new_security_origin = current_security_origin; - - // TODO(tyoshino): This should be fixed to check not only the last one but - // all redirect responses. - if (!current_security_origin->CanRequest(last_url)) { - // Follow http://www.w3.org/TR/cors/#redirect-steps - CrossOriginAccessControl::RedirectStatus redirect_status = - CrossOriginAccessControl::CheckRedirectLocation(new_url); - if (redirect_status != kRedirectSuccess) { - StringBuilder builder; - builder.Append("Redirect from '"); - builder.Append(last_url.GetString()); - builder.Append("' has been blocked by CORS policy: "); - CrossOriginAccessControl::RedirectErrorString(builder, redirect_status, - new_url); - error_message = builder.ToString(); - return false; - } - - // Step 5: perform resource sharing access check. - CrossOriginAccessControl::AccessStatus cors_status = - CrossOriginAccessControl::CheckAccess( - redirect_response, credentials_mode, current_security_origin.Get()); - if (cors_status != kAccessAllowed) { - StringBuilder builder; - builder.Append("Redirect from '"); - builder.Append(last_url.GetString()); - builder.Append("' has been blocked by CORS policy: "); - CrossOriginAccessControl::AccessControlErrorString( - builder, cors_status, redirect_response, - current_security_origin.Get(), new_request.GetRequestContext()); - error_message = builder.ToString(); - return false; - } - - RefPtr<SecurityOrigin> last_origin = SecurityOrigin::Create(last_url); - // Set request's origin to a globally unique identifier as specified in - // the step 10 in https://fetch.spec.whatwg.org/#http-redirect-fetch. - if (!last_origin->CanRequest(new_url)) { - options.security_origin = SecurityOrigin::CreateUnique(); - new_security_origin = options.security_origin; - } - } - - if (!current_security_origin->CanRequest(new_url)) { - new_request.ClearHTTPOrigin(); - new_request.SetHTTPOrigin(new_security_origin.Get()); - - options.cors_flag = true; - } - return true; -} - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControl.h b/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControl.h deleted file mode 100644 index 7238051..0000000 --- a/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControl.h +++ /dev/null
@@ -1,154 +0,0 @@ -/* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - */ - -#ifndef CrossOriginAccessControl_h -#define CrossOriginAccessControl_h - -#include "platform/PlatformExport.h" -#include "platform/loader/fetch/ResourceLoaderOptions.h" -#include "platform/loader/fetch/ResourceRequest.h" -#include "platform/wtf/Allocator.h" -#include "platform/wtf/Forward.h" -#include "platform/wtf/HashSet.h" - -namespace blink { - -using HTTPHeaderSet = HashSet<String, CaseFoldingHash>; - -struct ResourceLoaderOptions; -class ResourceRequest; -class ResourceResponse; -class SecurityOrigin; - -class PLATFORM_EXPORT CrossOriginAccessControl { - STATIC_ONLY(CrossOriginAccessControl); - - public: - // Enumerating the error conditions that the CORS - // access control check can report, including success. - // - // See |checkAccess()| and |accessControlErrorString()| which respectively - // produce and consume these error values, for precise meaning. - enum AccessStatus { - kAccessAllowed, - kInvalidResponse, - kAllowOriginMismatch, - kSubOriginMismatch, - kWildcardOriginNotAllowed, - kMissingAllowOriginHeader, - kMultipleAllowOriginValues, - kInvalidAllowOriginValue, - kDisallowCredentialsNotSetToTrue, - }; - - // Enumerating the error conditions that CORS preflight - // can report, including success. - // - // See |checkPreflight()| methods and |preflightErrorString()| which - // respectively produce and consume these error values, for precise meaning. - enum PreflightStatus { - kPreflightSuccess, - kPreflightInvalidStatus, - // "Access-Control-Allow-External:" - // ( https://wicg.github.io/cors-rfc1918/#headers ) specific error - // conditions: - kPreflightMissingAllowExternal, - kPreflightInvalidAllowExternal, - }; - - // Enumerating the error conditions that CORS redirect target URL - // checks can report, including success. - // - // See |checkRedirectLocation()| methods and |redirectErrorString()| which - // respectively produce and consume these error values, for precise meaning. - enum RedirectStatus { - kRedirectSuccess, - kRedirectDisallowedScheme, - kRedirectContainsCredentials, - }; - - // Perform a CORS access check on the response. Returns |kAccessAllowed| if - // access is allowed. Use |accessControlErrorString()| to construct a - // user-friendly error message for any of the other (error) conditions. - static AccessStatus CheckAccess(const ResourceResponse&, - WebURLRequest::FetchCredentialsMode, - const SecurityOrigin*); - - // Perform the required CORS checks on the response to a preflight request. - // Returns |kPreflightSuccess| if preflight response was successful. - // Use |preflightErrorString()| to construct a user-friendly error message - // for any of the other (error) conditions. - static PreflightStatus CheckPreflight(const ResourceResponse&); - - // Error checking for the currently experimental - // "Access-Control-Allow-External:" header. Shares error conditions with - // standard preflight checking. - static PreflightStatus CheckExternalPreflight(const ResourceResponse&); - - // Given a redirected-to URL, check if the location is allowed - // according to CORS. That is: - // - the URL has a CORS supported scheme and - // - the URL does not contain the userinfo production. - // - // Returns |kRedirectSuccess| in all other cases. Use - // |redirectErrorString()| to construct a user-friendly error - // message for any of the error conditions. - static RedirectStatus CheckRedirectLocation(const KURL&); - - static bool HandleRedirect(RefPtr<SecurityOrigin>, - ResourceRequest&, - const ResourceResponse&, - WebURLRequest::FetchCredentialsMode, - ResourceLoaderOptions&, - String&); - - // Stringify errors from CORS access checks, preflight or redirect checks. - static void AccessControlErrorString(StringBuilder&, - AccessStatus, - const ResourceResponse&, - const SecurityOrigin*, - WebURLRequest::RequestContext); - static void PreflightErrorString(StringBuilder&, - PreflightStatus, - const ResourceResponse&); - static void RedirectErrorString(StringBuilder&, RedirectStatus, const KURL&); - - static bool IsOnAccessControlResponseHeaderWhitelist(const String&); - - static ResourceRequest CreateAccessControlPreflightRequest( - const ResourceRequest&); - - static void ParseAccessControlExposeHeadersAllowList( - const String& header_value, - HTTPHeaderSet&); - - static void ExtractCorsExposedHeaderNamesList(const ResourceResponse&, - HTTPHeaderSet&); -}; - -} // namespace blink - -#endif // CrossOriginAccessControl_h
diff --git a/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControlTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControlTest.cpp deleted file mode 100644 index 9bab708..0000000 --- a/third_party/WebKit/Source/platform/loader/fetch/CrossOriginAccessControlTest.cpp +++ /dev/null
@@ -1,179 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "platform/loader/fetch/CrossOriginAccessControl.h" - -#include "platform/loader/fetch/ResourceRequest.h" -#include "platform/weborigin/SecurityOrigin.h" -#include "platform/wtf/RefPtr.h" -#include "platform/wtf/text/WTFString.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace blink { - -namespace { - -TEST(CreateAccessControlPreflightRequestTest, LexicographicalOrder) { - ResourceRequest request; - request.AddHTTPHeaderField("Orange", "Orange"); - request.AddHTTPHeaderField("Apple", "Red"); - request.AddHTTPHeaderField("Kiwifruit", "Green"); - request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); - request.AddHTTPHeaderField("Strawberry", "Red"); - - ResourceRequest preflight = - CrossOriginAccessControl::CreateAccessControlPreflightRequest(request); - - EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry", - preflight.HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(CreateAccessControlPreflightRequestTest, ExcludeSimpleHeaders) { - ResourceRequest request; - request.AddHTTPHeaderField("Accept", "everything"); - request.AddHTTPHeaderField("Accept-Language", "everything"); - request.AddHTTPHeaderField("Content-Language", "everything"); - request.AddHTTPHeaderField("Save-Data", "on"); - - ResourceRequest preflight = - CrossOriginAccessControl::CreateAccessControlPreflightRequest(request); - - // Do not emit empty-valued headers; an empty list of non-"CORS safelisted" - // request headers should cause "Access-Control-Request-Headers:" to be - // left out in the preflight request. - EXPECT_EQ(g_null_atom, - preflight.HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(CreateAccessControlPreflightRequestTest, ExcludeSimpleContentTypeHeader) { - ResourceRequest request; - request.AddHTTPHeaderField("Content-Type", "text/plain"); - - ResourceRequest preflight = - CrossOriginAccessControl::CreateAccessControlPreflightRequest(request); - - // Empty list also; see comment in test above. - EXPECT_EQ(g_null_atom, - preflight.HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(CreateAccessControlPreflightRequestTest, IncludeNonSimpleHeader) { - ResourceRequest request; - request.AddHTTPHeaderField("X-Custom-Header", "foobar"); - - ResourceRequest preflight = - CrossOriginAccessControl::CreateAccessControlPreflightRequest(request); - - EXPECT_EQ("x-custom-header", - preflight.HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(CreateAccessControlPreflightRequestTest, - IncludeNonSimpleContentTypeHeader) { - ResourceRequest request; - request.AddHTTPHeaderField("Content-Type", "application/octet-stream"); - - ResourceRequest preflight = - CrossOriginAccessControl::CreateAccessControlPreflightRequest(request); - - EXPECT_EQ("content-type", - preflight.HttpHeaderField("Access-Control-Request-Headers")); -} - -TEST(ParseAccessControlExposeHeadersAllowListTest, ValidInput) { - HTTPHeaderSet set; - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("valid", - set); - EXPECT_EQ(1U, set.size()); - EXPECT_TRUE(set.Contains("valid")); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("a,b", - set); - EXPECT_EQ(2U, set.size()); - EXPECT_TRUE(set.Contains("a")); - EXPECT_TRUE(set.Contains("b")); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( - " a , b ", set); - EXPECT_EQ(2U, set.size()); - EXPECT_TRUE(set.Contains("a")); - EXPECT_TRUE(set.Contains("b")); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( - " \t \t\t a", set); - EXPECT_EQ(1U, set.size()); - EXPECT_TRUE(set.Contains("a")); -} - -TEST(ParseAccessControlExposeHeadersAllowListTest, DuplicatedEntries) { - HTTPHeaderSet set; - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("a, a", - set); - EXPECT_EQ(1U, set.size()); - EXPECT_TRUE(set.Contains("a")); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("a, a, b", - set); - EXPECT_EQ(2U, set.size()); - EXPECT_TRUE(set.Contains("a")); - EXPECT_TRUE(set.Contains("b")); -} - -TEST(ParseAccessControlExposeHeadersAllowListTest, InvalidInput) { - HTTPHeaderSet set; - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( - "not valid", set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("///", - set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("/a/", - set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList(",", set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList(" , ", - set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList(" , a", - set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("a , ", - set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList("", set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList(" ", set); - EXPECT_TRUE(set.IsEmpty()); - - set.clear(); - // U+0141 which is 'A' (0x41) + 0x100. - CrossOriginAccessControl::ParseAccessControlExposeHeadersAllowList( - String::FromUTF8("\xC5\x81"), set); - EXPECT_TRUE(set.IsEmpty()); -} - -} // namespace - -} // namespace blink
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp index 1221a67..36035f20b 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchParameters.cpp
@@ -25,7 +25,6 @@ #include "platform/loader/fetch/FetchParameters.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/ResourceFetcher.h" #include "platform/weborigin/KURL.h" #include "platform/weborigin/SecurityOrigin.h"
diff --git a/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.h b/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.h index 789352a..16427cb7 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.h +++ b/third_party/WebKit/Source/platform/loader/fetch/FetchUtils.h
@@ -39,7 +39,7 @@ // Used by e.g. the CORS check algorithm to check if the FetchCredentialsMode // should be treated as equivalent to "include" in the Fetch spec. static bool ShouldTreatCredentialsModeAsInclude( - WebURLRequest::FetchCredentialsMode credentials_mode) { + const WebURLRequest::FetchCredentialsMode credentials_mode) { return credentials_mode == WebURLRequest::kFetchCredentialsModeInclude || credentials_mode == WebURLRequest::kFetchCredentialsModePassword; }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp index 155f2bb5e..2235fdd 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/Resource.cpp
@@ -38,7 +38,6 @@ #include "platform/WebTaskRunner.h" #include "platform/instrumentation/tracing/TraceEvent.h" #include "platform/loader/fetch/CachedMetadata.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/FetchInitiatorTypeNames.h" #include "platform/loader/fetch/FetchParameters.h" #include "platform/loader/fetch/IntegrityMetadata.h"
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp index 259d153..440e1e2 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.cpp
@@ -32,7 +32,6 @@ #include "platform/SharedBuffer.h" #include "platform/exported/WrappedResourceRequest.h" #include "platform/exported/WrappedResourceResponse.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/FetchContext.h" #include "platform/loader/fetch/Resource.h" #include "platform/loader/fetch/ResourceError.h" @@ -44,6 +43,7 @@ #include "platform/wtf/PtrUtil.h" #include "platform/wtf/text/StringBuilder.h" #include "public/platform/Platform.h" +#include "public/platform/WebCORS.h" #include "public/platform/WebCachePolicy.h" #include "public/platform/WebData.h" #include "public/platform/WebURLError.h" @@ -276,12 +276,14 @@ RefPtr<SecurityOrigin> source_origin = options.security_origin; if (!source_origin.Get()) source_origin = Context().GetSecurityOrigin(); - - String cors_error_msg; - if (!CrossOriginAccessControl::HandleRedirect( - source_origin, new_request, redirect_response, - fetch_credentials_mode, resource_->MutableOptions(), - cors_error_msg)) { + WebSecurityOrigin source_web_origin(source_origin.Get()); + WrappedResourceRequest new_request_wrapper(new_request); + WebString cors_error_msg; + if (!WebCORS::HandleRedirect(source_web_origin, new_request_wrapper, + WrappedResourceResponse(redirect_response), + fetch_credentials_mode, + resource_->MutableOptions(), + cors_error_msg)) { resource_->SetCORSStatus(CORSStatus::kFailed); if (!unused_preload) { @@ -293,6 +295,8 @@ ResourceRequestBlockedReason::kOther); return false; } + + source_origin = source_web_origin; } if (resource_type == Resource::kImage && fetcher_->ShouldDeferImageLoad(new_url)) { @@ -427,12 +431,12 @@ ? resource_->GetResponse() : response; - CrossOriginAccessControl::AccessStatus cors_status = - CrossOriginAccessControl::CheckAccess( - response_for_access_control, - initial_request.GetFetchCredentialsMode(), source_origin); + WebCORS::AccessStatus cors_status = + WebCORS::CheckAccess(WrappedResourceResponse(response_for_access_control), + initial_request.GetFetchCredentialsMode(), + WebSecurityOrigin(source_origin)); - if (cors_status == CrossOriginAccessControl::AccessStatus::kAccessAllowed) + if (cors_status == WebCORS::AccessStatus::kAccessAllowed) return CORSStatus::kSuccessful; String resource_type = Resource::ResourceTypeToString( @@ -444,10 +448,9 @@ error_msg.Append("' from origin '"); error_msg.Append(source_origin->ToString()); error_msg.Append("' has been blocked by CORS policy: "); - - CrossOriginAccessControl::AccessControlErrorString( - error_msg, cors_status, response_for_access_control, source_origin, - initial_request.GetRequestContext()); + error_msg.Append(WebCORS::AccessControlErrorString( + cors_status, WrappedResourceResponse(response_for_access_control), + WebSecurityOrigin(source_origin), initial_request.GetRequestContext())); return CORSStatus::kFailed; }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h index 1488621..275d101c3 100644 --- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h +++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h
@@ -34,7 +34,6 @@ #include "platform/PlatformExport.h" #include "platform/heap/Handle.h" #include "platform/heap/SelfKeepAlive.h" -#include "platform/loader/fetch/CrossOriginAccessControl.h" #include "platform/loader/fetch/Resource.h" #include "platform/loader/fetch/ResourceLoadScheduler.h" #include "platform/loader/fetch/ResourceLoaderOptions.h"
diff --git a/third_party/WebKit/Source/platform/network/HTTPNames.json5 b/third_party/WebKit/Source/platform/network/HTTPNames.json5 index 2d504aa..4fb891c8 100644 --- a/third_party/WebKit/Source/platform/network/HTTPNames.json5 +++ b/third_party/WebKit/Source/platform/network/HTTPNames.json5
@@ -16,6 +16,8 @@ "Access-Control-Allow-Headers", "Access-Control-Allow-Methods", "Access-Control-Allow-Origin", + "Access-Control-Allow-Suborigin", + "Access-Control-Allow-Credentials", "Access-Control-Expose-Headers", "Access-Control-Max-Age", "Access-Control-Request-External",
diff --git a/third_party/WebKit/public/platform/WebCORS.h b/third_party/WebKit/public/platform/WebCORS.h new file mode 100644 index 0000000..5c528329 --- /dev/null +++ b/third_party/WebKit/public/platform/WebCORS.h
@@ -0,0 +1,160 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WebCORS_h +#define WebCORS_h + +#include "platform/loader/fetch/ResourceLoaderOptions.h" +#include "platform/wtf/HashSet.h" +#include "platform/wtf/text/StringHash.h" +#include "public/platform/WebString.h" +#include "public/platform/WebURL.h" +#include "public/platform/WebURLRequest.h" + +namespace blink { + +class WebURLResponse; +class WebSecurityOrigin; + +namespace WebCORS { + +typedef HashSet<String, CaseFoldingHash> HTTPHeaderSet; + +// Enumerating the error conditions that the CORS +// access control check can report, including success. +// +// See |CheckAccess()| and |AccessControlErrorString()| which respectively +// produce and consume these error values, for precise meaning. +enum AccessStatus { + kAccessAllowed, + kInvalidResponse, + kAllowOriginMismatch, + kSubOriginMismatch, + kWildcardOriginNotAllowed, + kMissingAllowOriginHeader, + kMultipleAllowOriginValues, + kInvalidAllowOriginValue, + kDisallowCredentialsNotSetToTrue, +}; + +// Enumerating the error conditions that CORS preflight +// can report, including success. +// +// See |CheckPreflight()| methods and |PreflightErrorString()| which +// respectively produce and consume these error values, for precise meaning. +enum PreflightStatus { + kPreflightSuccess, + kPreflightInvalidStatus, + // "Access-Control-Allow-External:" + // ( https://wicg.github.io/cors-rfc1918/#headers ) specific error + // conditions: + kPreflightMissingAllowExternal, + kPreflightInvalidAllowExternal, +}; + +// Enumerating the error conditions that CORS redirect target URL +// checks can report, including success. +// +// See |CheckRedirectLocation()| methods and |RedirectErrorString()| which +// respectively produce and consume these error values, for precise meaning. +enum RedirectStatus { + kRedirectSuccess, + kRedirectDisallowedScheme, + kRedirectContainsCredentials, +}; + +// Perform a CORS access check on the response. Returns |kAccessAllowed| if +// access is allowed. Use |AccessControlErrorString()| to construct a +// user-friendly error message for any of the other (error) conditions. +BLINK_PLATFORM_EXPORT AccessStatus +CheckAccess(const WebURLResponse&, + WebURLRequest::FetchCredentialsMode, + const WebSecurityOrigin&); + +// Given a redirected-to URL, check if the location is allowed +// according to CORS. That is: +// - the URL has a CORS supported scheme and +// - the URL does not contain the userinfo production. +// +// Returns |kRedirectSuccess| in all other cases. Use +// |RedirectErrorString()| to construct a user-friendly error +// message for any of the error conditions. +BLINK_PLATFORM_EXPORT RedirectStatus CheckRedirectLocation(const WebURL&); + +// Perform the required CORS checks on the response to a preflight request. +// Returns |kPreflightSuccess| if preflight response was successful. +// Use |PreflightErrorString()| to construct a user-friendly error message +// for any of the other (error) conditions. +BLINK_PLATFORM_EXPORT PreflightStatus CheckPreflight(const WebURLResponse&); + +// Error checking for the currently experimental +// "Access-Control-Allow-External:" header. Shares error conditions with +// standard preflight checking. +BLINK_PLATFORM_EXPORT PreflightStatus +CheckExternalPreflight(const WebURLResponse&); + +BLINK_PLATFORM_EXPORT WebURLRequest +CreateAccessControlPreflightRequest(const WebURLRequest&); + +// TODO(tyoshino): Using platform/loader/fetch/ResourceLoaderOptions violates +// the DEPS rule. This will be fixed soon by making HandleRedirect() not +// depending on ResourceLoaderOptions. +BLINK_PLATFORM_EXPORT bool HandleRedirect(WebSecurityOrigin&, + WebURLRequest&, + const WebURLResponse&, + WebURLRequest::FetchCredentialsMode, + ResourceLoaderOptions&, + WebString&); + +// Stringify errors from CORS access checks, preflight or redirect checks. +BLINK_PLATFORM_EXPORT WebString +AccessControlErrorString(const AccessStatus, + const WebURLResponse&, + const WebSecurityOrigin&, + const WebURLRequest::RequestContext); + +BLINK_PLATFORM_EXPORT WebString PreflightErrorString(const PreflightStatus, + const WebURLResponse&); + +BLINK_PLATFORM_EXPORT WebString RedirectErrorString(const RedirectStatus, + const WebURL&); + +BLINK_PLATFORM_EXPORT void ParseAccessControlExposeHeadersAllowList( + const WebString&, + HTTPHeaderSet&); + +BLINK_PLATFORM_EXPORT void ExtractCorsExposedHeaderNamesList( + const WebURLResponse&, + HTTPHeaderSet&); + +BLINK_PLATFORM_EXPORT bool IsOnAccessControlResponseHeaderWhitelist( + const WebString&); + +} // namespace WebCORS + +} // namespace blink + +#endif // WebCORS_h
diff --git a/third_party/WebKit/public/platform/WebURLResponse.h b/third_party/WebKit/public/platform/WebURLResponse.h index 1473594b..23efd60 100644 --- a/third_party/WebKit/public/platform/WebURLResponse.h +++ b/third_party/WebKit/public/platform/WebURLResponse.h
@@ -249,6 +249,7 @@ // The headers that should be exposed according to CORS. Only guaranteed // to be set if the response was served by a ServiceWorker. + BLINK_PLATFORM_EXPORT WebVector<WebString> CorsExposedHeaderNames() const; BLINK_PLATFORM_EXPORT void SetCorsExposedHeaderNames( const WebVector<WebString>&);
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py index ff2ae57..55500ad 100755 --- a/tools/gn/bootstrap/bootstrap.py +++ b/tools/gn/bootstrap/bootstrap.py
@@ -550,8 +550,6 @@ 'base/trace_event/memory_peak_detector.cc', 'base/trace_event/memory_usage_estimator.cc', 'base/trace_event/process_memory_dump.cc', - 'base/trace_event/process_memory_maps.cc', - 'base/trace_event/process_memory_totals.cc', 'base/trace_event/sharded_allocation_register.cc', 'base/trace_event/trace_buffer.cc', 'base/trace_event/trace_config.cc',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index bf3ca92..4f8db58 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -54361,11 +54361,17 @@ </histogram> <histogram name="PaymentRequest.CheckoutFunnel.Completed" enum="BooleanHit"> + <obsolete> + M62+ Part of PaymentRequest.Events + </obsolete> <owner>sebsg@chromium.org</owner> <summary>When the merchant has processed the user's Payment Request.</summary> </histogram> <histogram name="PaymentRequest.CheckoutFunnel.Initiated" enum="BooleanHit"> + <obsolete> + M62+ Part of PaymentRequest.Events + </obsolete> <owner>sebsg@chromium.org</owner> <summary>When a Payment Request gets initiated by the user.</summary> </histogram> @@ -54379,6 +54385,9 @@ </histogram> <histogram name="PaymentRequest.CheckoutFunnel.PayClicked" enum="BooleanHit"> + <obsolete> + M62+ Part of PaymentRequest.Events + </obsolete> <owner>sebsg@chromium.org</owner> <summary> When the user clicks the "pay" button in the Payment Request UI. @@ -54387,6 +54396,9 @@ <histogram name="PaymentRequest.CheckoutFunnel.ReceivedInstrumentDetails" enum="BooleanHit"> + <obsolete> + M62+ Part of PaymentRequest.Events + </obsolete> <owner>sebsg@chromium.org</owner> <summary> When the browser retrieves the instrument details from the payment app to @@ -54395,6 +54407,9 @@ </histogram> <histogram name="PaymentRequest.CheckoutFunnel.Shown" enum="BooleanHit"> + <obsolete> + M62+ Part of PaymentRequest.Events + </obsolete> <owner>sebsg@chromium.org</owner> <summary> When the Payment Request UI gets shown after initialization. @@ -54403,6 +54418,9 @@ <histogram name="PaymentRequest.CheckoutFunnel.SkippedShow" enum="BooleanSkipped"> + <obsolete> + M62+ Part of PaymentRequest.Events + </obsolete> <owner>sebsg@chromium.org</owner> <summary> When the Payment Request UI gets skipped to go directly to the payment app.
diff --git a/tools/perf/benchmarks/loading.py b/tools/perf/benchmarks/loading.py index 93b69b9..cffbf0e 100644 --- a/tools/perf/benchmarks/loading.py +++ b/tools/perf/benchmarks/loading.py
@@ -42,7 +42,9 @@ class StoryExpectations(story.expectations.StoryExpectations): def SetExpectations(self): self.DisableStory( - 'uol.com.br', [story.expectations.ALL_LINUX], 'crbug.com/723783') + 'uol.com.br', [story.expectations.ALL_LINUX], 'crbug.com/752611') + self.DisableStory( + 'Orange', [story.expectations.ALL_WIN], 'crbug.com/723783') return StoryExpectations() @classmethod
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py index 9ef93ce4..f664fd27 100644 --- a/tools/perf/benchmarks/smoothness.py +++ b/tools/perf/benchmarks/smoothness.py
@@ -588,7 +588,6 @@ return StoryExpectations() -@benchmark.Disabled('android') # http://crbug.com/513699 @benchmark.Owner(emails=['cblume@chromium.org']) class SmoothnessGpuImageDecodingCases(_Smoothness): """Measures decoding statistics for jpeg images with GPU rasterization.
diff --git a/ui/aura/gestures/gesture_recognizer_unittest.cc b/ui/aura/gestures/gesture_recognizer_unittest.cc index 8d4bf832..4294c4f 100644 --- a/ui/aura/gestures/gesture_recognizer_unittest.cc +++ b/ui/aura/gestures/gesture_recognizer_unittest.cc
@@ -1700,8 +1700,8 @@ EXPECT_TRUE(delegate->tap_cancel()); EXPECT_TRUE(delegate->scroll_begin()); EXPECT_TRUE(delegate->scroll_update()); - EXPECT_EQ(15, delegate->scroll_x_hint()); - EXPECT_EQ(15, delegate->scroll_y_hint()); + EXPECT_EQ(10, delegate->scroll_x_hint()); + EXPECT_EQ(10, delegate->scroll_y_hint()); delegate->Reset(); @@ -3709,7 +3709,7 @@ EXPECT_TRUE(delegate->scroll_update()); // 3 px consumed by touch slop region. EXPECT_EQ(-1, delegate->scroll_y()); - EXPECT_EQ(-4, delegate->scroll_y_hint()); + EXPECT_EQ(-1, delegate->scroll_y_hint()); delegate->Reset(); @@ -4096,7 +4096,7 @@ EXPECT_TRUE(delegate->scroll_begin()); EXPECT_TRUE(delegate->scroll_update()); EXPECT_NEAR(0.1, delegate->scroll_x(), 0.0001); - EXPECT_FLOAT_EQ(3.1f, delegate->scroll_x_hint()); + EXPECT_NEAR(0.1, delegate->scroll_x_hint(), 0.0001); delegate->Reset(); ui::TouchEvent move4(
diff --git a/ui/aura/mus/mus_context_factory.cc b/ui/aura/mus/mus_context_factory.cc index 1da45b6..6cab93e48 100644 --- a/ui/aura/mus/mus_context_factory.cc +++ b/ui/aura/mus/mus_context_factory.cc
@@ -8,11 +8,11 @@ #include "base/memory/ptr_util.h" #include "cc/base/switches.h" #include "components/viz/common/gpu/context_provider.h" +#include "components/viz/host/renderer_settings_creation.h" #include "services/ui/public/cpp/gpu/gpu.h" #include "ui/aura/mus/window_port_mus.h" #include "ui/aura/window_tree_host.h" #include "ui/compositor/compositor_switches.h" -#include "ui/compositor/compositor_util.h" #include "ui/display/display_switches.h" #include "ui/gfx/switches.h" #include "ui/gl/gl_bindings.h" @@ -40,7 +40,7 @@ MusContextFactory::MusContextFactory(ui::Gpu* gpu) : gpu_(gpu), resource_settings_( - ui::CreateResourceSettings(CreateBufferToTextureTargetMap())), + viz::CreateResourceSettings(CreateBufferToTextureTargetMap())), weak_ptr_factory_(this) {} MusContextFactory::~MusContextFactory() {}
diff --git a/ui/base/ui_base_switches.cc b/ui/base/ui_base_switches.cc index ed2ef37..4267481 100644 --- a/ui/base/ui_base_switches.cc +++ b/ui/base/ui_base_switches.cc
@@ -31,6 +31,9 @@ const char kEnableMergeKeyCharEvents[] = "enable-merge-key-char-events"; #endif +// Disables layer-edge anti-aliasing in the compositor. +const char kDisableCompositedAntialiasing[] = "disable-composited-antialiasing"; + // Disables use of DWM composition for top level windows. const char kDisableDwmComposition[] = "disable-dwm-composition"; @@ -43,6 +46,13 @@ // Enables touch event based drag and drop. const char kEnableTouchDragDrop[] = "enable-touch-drag-drop"; +// TODO(dcastagna): Draw debug quad borders only when it is actually +// an overlay candidate. +// Renders a border around GL composited overlay candidate quads to +// help debug and study overlay support. +const char kGlCompositedOverlayCandidateQuadBorder[] = + "gl-composited-overlay-candidate-quad-border"; + // The language file that we want to try to open. Of the form // language[-country] where language is the 2 letter code from ISO-639. const char kLang[] = "lang"; @@ -79,4 +89,24 @@ // throughout Chrome (not just top Chrome). const char kExtendMdToSecondaryUi[] = "secondary-ui-md"; +// Disable partial swap which is needed for some OpenGL drivers / emulators. +const char kUIDisablePartialSwap[] = "ui-disable-partial-swap"; + +// Visualize overdraw by color-coding elements based on if they have other +// elements drawn underneath. This is good for showing where the UI might be +// doing more rendering work than necessary. The colors are hinting at the +// amount of overdraw on your screen for each pixel, as follows: +// +// True color: No overdraw. +// Blue: Overdrawn once. +// Green: Overdrawn twice. +// Pink: Overdrawn three times. +// Red: Overdrawn four or more times. +const char kShowOverdrawFeedback[] = "show-overdraw-feedback"; + +// Disable re-use of non-exact resources to fulfill ResourcePool requests. +// Intended only for use in layout or pixel tests to reduce noise. +const char kDisallowNonExactResourceReuse[] = + "disallow-non-exact-resource-reuse"; + } // namespace switches
diff --git a/ui/base/ui_base_switches.h b/ui/base/ui_base_switches.h index 69e8cc1..b3a4634 100644 --- a/ui/base/ui_base_switches.h +++ b/ui/base/ui_base_switches.h
@@ -8,6 +8,7 @@ #define UI_BASE_UI_BASE_SWITCHES_H_ #include "base/compiler_specific.h" +#include "base/feature_list.h" #include "build/build_config.h" #include "ui/base/ui_base_export.h" @@ -25,11 +26,13 @@ UI_BASE_EXPORT extern const char kEnableMergeKeyCharEvents[]; #endif +UI_BASE_EXPORT extern const char kDisableCompositedAntialiasing[]; UI_BASE_EXPORT extern const char kDisableDwmComposition[]; UI_BASE_EXPORT extern const char kDisableNewVirtualKeyboardBehavior[]; UI_BASE_EXPORT extern const char kDisableTouchAdjustment[]; UI_BASE_EXPORT extern const char kDisableTouchDragDrop[]; UI_BASE_EXPORT extern const char kEnableTouchDragDrop[]; +UI_BASE_EXPORT extern const char kGlCompositedOverlayCandidateQuadBorder[]; UI_BASE_EXPORT extern const char kLang[]; UI_BASE_EXPORT extern const char kMaterialDesignInkDropAnimationSpeed[]; UI_BASE_EXPORT extern const char kMaterialDesignInkDropAnimationSpeedFast[]; @@ -40,6 +43,11 @@ UI_BASE_EXPORT extern const char kTopChromeMDMaterialHybrid[]; UI_BASE_EXPORT extern const char kTopChromeMDNonMaterial[]; UI_BASE_EXPORT extern const char kExtendMdToSecondaryUi[]; +UI_BASE_EXPORT extern const char kUIDisablePartialSwap[]; +UI_BASE_EXPORT extern const char kShowOverdrawFeedback[]; + +// Test related. +UI_BASE_EXPORT extern const char kDisallowNonExactResourceReuse[]; } // namespace switches
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn index 27ea8d3..114ac26 100644 --- a/ui/compositor/BUILD.gn +++ b/ui/compositor/BUILD.gn
@@ -27,8 +27,6 @@ "compositor_observer.h", "compositor_switches.cc", "compositor_switches.h", - "compositor_util.cc", - "compositor_util.h", "compositor_vsync_manager.cc", "compositor_vsync_manager.h", "debug_utils.cc", @@ -92,6 +90,7 @@ "//components/viz/service", "//gpu/command_buffer/common", "//skia", + "//ui/base", "//ui/display", "//ui/gfx", "//ui/gfx/animation",
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc index 262ac1f..fe79595 100644 --- a/ui/compositor/compositor.cc +++ b/ui/compositor/compositor.cc
@@ -39,6 +39,7 @@ #include "components/viz/host/host_frame_sink_manager.h" #include "components/viz/service/frame_sinks/frame_sink_manager_impl.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/base/ui_base_switches.h" #include "ui/compositor/compositor_observer.h" #include "ui/compositor/compositor_switches.h" #include "ui/compositor/compositor_vsync_manager.h" @@ -170,7 +171,7 @@ gpu::MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE; settings.disallow_non_exact_resource_reuse = - command_line->HasSwitch(cc::switches::kDisallowNonExactResourceReuse); + command_line->HasSwitch(switches::kDisallowNonExactResourceReuse); settings.wait_for_all_pipeline_stages_before_draw = command_line->HasSwitch(cc::switches::kRunAllCompositorStagesBeforeDraw);
diff --git a/ui/compositor/compositor_switches.cc b/ui/compositor/compositor_switches.cc index 4833b4f..9d6c470c 100644 --- a/ui/compositor/compositor_switches.cc +++ b/ui/compositor/compositor_switches.cc
@@ -21,9 +21,6 @@ // maximum. const char kLimitFps[] = "limit-fps"; -// Disable partial swap which is needed for some OpenGL drivers / emulators. -const char kUIDisablePartialSwap[] = "ui-disable-partial-swap"; - const char kUIEnableRGBA4444Textures[] = "ui-enable-rgba-4444-textures"; const char kUIEnableZeroCopy[] = "ui-enable-zero-copy";
diff --git a/ui/compositor/compositor_switches.h b/ui/compositor/compositor_switches.h index 9f669a4..5c03be48 100644 --- a/ui/compositor/compositor_switches.h +++ b/ui/compositor/compositor_switches.h
@@ -12,7 +12,6 @@ COMPOSITOR_EXPORT extern const char kEnableHardwareOverlays[]; COMPOSITOR_EXPORT extern const char kEnablePixelOutputInTests[]; COMPOSITOR_EXPORT extern const char kLimitFps[]; -COMPOSITOR_EXPORT extern const char kUIDisablePartialSwap[]; COMPOSITOR_EXPORT extern const char kUIEnableRGBA4444Textures[]; COMPOSITOR_EXPORT extern const char kUIEnableZeroCopy[]; COMPOSITOR_EXPORT extern const char kUIShowPaintRects[];
diff --git a/ui/compositor/compositor_util.h b/ui/compositor/compositor_util.h deleted file mode 100644 index 40e31b6..0000000 --- a/ui/compositor/compositor_util.h +++ /dev/null
@@ -1,30 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef UI_COMPOSITOR_COMPOSITOR_UTIL_H_ -#define UI_COMPOSITOR_COMPOSITOR_UTIL_H_ - -#include <stdint.h> - -#include "components/viz/common/resources/buffer_to_texture_target_map.h" -#include "ui/compositor/compositor_export.h" - -namespace viz { -class RendererSettings; -class ResourceSettings; -} - -namespace ui { - -// |image_targets| is a map from every supported pair of GPU memory buffer -// usage/format to its GL texture target. -COMPOSITOR_EXPORT viz::ResourceSettings CreateResourceSettings( - const viz::BufferToTextureTargetMap& image_targets); - -COMPOSITOR_EXPORT viz::RendererSettings CreateRendererSettings( - const viz::BufferToTextureTargetMap& image_targets); - -} // namespace ui - -#endif // UI_COMPOSITOR_COMPOSITOR_UTIL_H_
diff --git a/ui/events/gesture_detection/gesture_provider.cc b/ui/events/gesture_detection/gesture_provider.cc index 2c0c9bf..39b8a2d 100644 --- a/ui/events/gesture_detection/gesture_provider.cc +++ b/ui/events/gesture_detection/gesture_provider.cc
@@ -323,8 +323,8 @@ if (!scroll_event_sent_) { // Note that scroll start hints are in distance traveled, where // scroll deltas are in the opposite direction. - GestureEventDetails scroll_details( - ET_GESTURE_SCROLL_BEGIN, -raw_distance_x, -raw_distance_y); + GestureEventDetails scroll_details(ET_GESTURE_SCROLL_BEGIN, -distance_x, + -distance_y); scroll_details.set_device_type(GestureDeviceType::DEVICE_TOUCHSCREEN); // Scroll focus point always starts with the first touch down point.
diff --git a/ui/events/gesture_detection/gesture_provider_unittest.cc b/ui/events/gesture_detection/gesture_provider_unittest.cc index ad6d1c98..50390db 100644 --- a/ui/events/gesture_detection/gesture_provider_unittest.cc +++ b/ui/events/gesture_detection/gesture_provider_unittest.cc
@@ -917,8 +917,11 @@ // Generate a scroll gesture and verify that the resulting scroll begin event // has the expected hint values. TEST_F(GestureProviderTest, ScrollBeginValues) { - const float delta_x = 13; - const float delta_y = 89; + const float delta_x = 14; + const float delta_y = 48; + // These are the deltas after subtracting slop region and railing. + const float delta_x_hint = 0; + const float delta_y_hint = 40.32f; const base::TimeTicks event_time = TimeTicks::Now(); @@ -944,8 +947,8 @@ const GestureEventData* scroll_begin_gesture = GetActiveScrollBeginEvent(); ASSERT_TRUE(scroll_begin_gesture); - EXPECT_EQ(delta_x, scroll_begin_gesture->details.scroll_x_hint()); - EXPECT_EQ(delta_y, scroll_begin_gesture->details.scroll_y_hint()); + EXPECT_EQ(delta_x_hint, scroll_begin_gesture->details.scroll_x_hint()); + EXPECT_EQ(delta_y_hint, scroll_begin_gesture->details.scroll_y_hint()); } // The following three tests verify that slop regions are checked for
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h index fbe0fef..517bd40 100644 --- a/ui/gfx/native_widget_types.h +++ b/ui/gfx/native_widget_types.h
@@ -133,12 +133,6 @@ typedef ui::ViewAndroid* NativeView; typedef ui::WindowAndroid* NativeWindow; typedef jobject NativeEvent; -#elif defined(OS_FUCHSIA) -// TODO(fuchsia): Update when we have a plan for UI on Fuchsia. -typedef void* NativeCursor; -typedef void* NativeView; -typedef void* NativeWindow; -typedef void* NativeEvent; #else #error Unknown build environment. #endif @@ -203,10 +197,6 @@ #elif defined(USE_OZONE) typedef int32_t AcceleratedWidget; constexpr AcceleratedWidget kNullAcceleratedWidget = 0; -#elif defined(OS_FUCHSIA) -// TODO(fuchsia): Update when we have a plan for UI on Fuchsia. -typedef void* AcceleratedWidget; -constexpr AcceleratedWidget kNullAcceleratedWidget = 0; #else #error unknown platform #endif
diff --git a/ui/views/animation/ink_drop_host_view.cc b/ui/views/animation/ink_drop_host_view.cc index 1856e89..3124f826 100644 --- a/ui/views/animation/ink_drop_host_view.cc +++ b/ui/views/animation/ink_drop_host_view.cc
@@ -118,7 +118,8 @@ InkDropHostView::InkDropHostView() : ink_drop_mode_(InkDropMode::OFF), ink_drop_(nullptr), - ink_drop_visible_opacity_(kInkDropVisibleOpacity), + ink_drop_visible_opacity_( + PlatformStyle::kUseRipples ? kInkDropVisibleOpacity : 0), old_paint_to_layer_(false), destroying_(false) {} @@ -277,7 +278,7 @@ InkDrop* InkDropHostView::GetInkDrop() { if (!ink_drop_) { - if (ink_drop_mode_ == InkDropMode::OFF || !PlatformStyle::kUseRipples) + if (ink_drop_mode_ == InkDropMode::OFF) ink_drop_ = base::MakeUnique<InkDropStub>(); else ink_drop_ = CreateInkDrop();
diff --git a/ui/views/controls/button/toggle_button_unittest.cc b/ui/views/controls/button/toggle_button_unittest.cc index e0a6e2e8..ac61914 100644 --- a/ui/views/controls/button/toggle_button_unittest.cc +++ b/ui/views/controls/button/toggle_button_unittest.cc
@@ -10,7 +10,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/events/event_utils.h" #include "ui/events/test/event_generator.h" -#include "ui/views/style/platform_style.h" #include "ui/views/test/views_test_base.h" namespace views { @@ -95,11 +94,7 @@ button()->OnMousePressed(ui::MouseEvent( ui::ET_MOUSE_PRESSED, center, center, ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); - // On platforms with no ripples, there should never be an ink drop layer. - if (PlatformStyle::kUseRipples) - EXPECT_EQ(1, counter()); - else - EXPECT_EQ(0, counter()); + EXPECT_EQ(1, counter()); delete button(); EXPECT_EQ(0, counter()); } @@ -108,10 +103,7 @@ // ToggleButton has focus (and is showing a ripple). TEST_F(ToggleButtonTest, ShutdownWithFocus) { button()->RequestFocus(); - if (PlatformStyle::kUseRipples) - EXPECT_EQ(1, counter()); - else - EXPECT_EQ(0, counter()); + EXPECT_EQ(1, counter()); } // Verify that ToggleButton::accepts_events_ works as expected.