diff --git a/DEPS b/DEPS index d5cca170..8a79caa7 100644 --- a/DEPS +++ b/DEPS
@@ -39,7 +39,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': '973d92cf91b21013361209e8a5c0c4685728847f', + 'skia_revision': 'a6bf4c54aaa3c1d1ae33f43af96a294c65bbd8fc', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -59,7 +59,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': 'a76a6d8bcb76077fa248b64c5d64791dc8f23771', + 'pdfium_revision': '32b639de35f905a5e5559f305d9032cde5ae5c77', # 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. @@ -187,7 +187,7 @@ Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'd1e9c4bbd95af9a089d224edf87fd0c3f33ece96', 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'd9abcae5ed8678a1b32bb8dad1b84eba82546910', # commit position 11290 + Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'e05d86dec0266615e60958c21bc5044c745e0eb4', # commit position 11304 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98', @@ -211,7 +211,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '8d5f2987a2d68d2b2ce30155c6bbcf8fb217692a', # commit position 11288 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'd1460028c85a0cccdec4e1c16e01ba1e55f97456', # commit position 11307 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), @@ -271,7 +271,7 @@ 'src/third_party/catapult': Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + - 'dc74f19fa849b17180f09cfdf3c5757a26e9a379', + 'b88898e20aa41708c89afa892a5de1c3af20ae04', 'src/third_party/openh264/src': Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
diff --git a/WATCHLISTS b/WATCHLISTS index 62caf9b..a25b1e7 100644 --- a/WATCHLISTS +++ b/WATCHLISTS
@@ -1230,9 +1230,7 @@ 'yuzo+watch@chromium.org'], 'activity_log': ['felt@chromium.org'], 'android_infobars': ['dfalcantara+watch@chromium.org'], - 'android_infra': ['yfriedman+watch@chromium.org', - 'klundberg+watch@chromium.org', - 'jbudorick+watch@chromium.org', + 'android_infra': ['jbudorick+watch@chromium.org', 'mikecase+watch@chromium.org'], 'android_media': ['avayvod+watch@chromium.org', 'mlamouri+watch-media@chromium.org'],
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc index aa81e00..1f311b22 100644 --- a/base/trace_event/memory_dump_manager.cc +++ b/base/trace_event/memory_dump_manager.cc
@@ -419,12 +419,15 @@ disabled_reason = "Dump failure, possibly related with sandboxing (crbug.com/461788)." " Try --no-sandbox."; - } else if (post_task_failed) { - disabled_reason = "The thread it was meant to dump onto is gone."; + } else if (post_task_failed && mdpinfo->task_runner) { + // Don't disable unbound dump providers. The utility thread is normally + // shutdown when disabling the trace and getting here in this case is + // expected. mdpinfo->disabled = true; + disabled_reason = "The thread it was meant to dump onto is gone."; } } - should_dump = !mdpinfo->disabled; + should_dump = !mdpinfo->disabled && !post_task_failed; } if (disabled_reason) {
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py index 61260c9d..c8b3386 100755 --- a/build/android/buildbot/bb_device_status_check.py +++ b/build/android/buildbot/bb_device_status_check.py
@@ -308,6 +308,9 @@ parser.add_argument('--adb-path', help='Absolute path to the adb binary to use.') parser.add_argument('--blacklist-file', help='Device blacklist JSON file.') + parser.add_argument('--known-devices-file', action='append', default=[], + dest='known_devices_files', + help='Path to known device lists.') parser.add_argument('-v', '--verbose', action='count', default=1, help='Log more information.') @@ -331,11 +334,16 @@ last_devices_path = os.path.join( args.out_dir, device_list.LAST_DEVICES_FILENAME) + args.known_devices_files.append(last_devices_path) + + expected_devices = set() try: - expected_devices = set( - device_list.GetPersistentDeviceList(last_devices_path)) + for path in args.known_devices_files: + if os.path.exists(path): + expected_devices.update(device_list.GetPersistentDeviceList(path)) except IOError: - expected_devices = set() + logging.warning('Problem reading %s, skipping.', path) + logging.info('Expected devices:') for device in expected_devices: logging.info(' %s', device) @@ -367,10 +375,10 @@ logging.info(' IMEI slice: %s', status.get('imei_slice')) logging.info(' WiFi IP: %s', status.get('wifi_ip')) - # Update the last devices file. - device_list.WritePersistentDeviceList( - last_devices_path, - [status['serial'] for status in statuses]) + # Update the last devices file(s). + for path in args.known_devices_files: + device_list.WritePersistentDeviceList( + path, [status['serial'] for status in statuses]) # Write device info to file for buildbot info display. if os.path.exists('/home/chrome-bot'):
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni index f8f469c..0795011 100644 --- a/build/config/sanitizers/sanitizers.gni +++ b/build/config/sanitizers/sanitizers.gni
@@ -89,6 +89,3 @@ assert( !is_debug || !(is_msan || is_lsan || is_tsan || is_ubsan || is_ubsan_vptr), "Sanitizers should generally be used in release (set is_debug=false).") - -assert(!(is_android && is_asan && !is_component_build), - "is_asan on Android requires is_component_build to be set")
diff --git a/build/config/win/console_app.gni b/build/config/win/console_app.gni new file mode 100644 index 0000000..cac2ef5 --- /dev/null +++ b/build/config/win/console_app.gni
@@ -0,0 +1,18 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/config/sanitizers/sanitizers.gni") + +declare_args() { + # If true, builds as a console app (rather than a windowed app), which allows + # logging to be printed to the user. This will cause a terminal window to pop + # up when the executable is not run from the command line, so should only be + # used for development. Only has an effect on Windows builds. + win_console_app = false +} + +if (is_win && is_asan) { + # AddressSanitizer build should be a console app since it writes to stderr. + win_console_app = true +}
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc index c6b12ba..475885c 100644 --- a/build/sanitizers/tsan_suppressions.cc +++ b/build/sanitizers/tsan_suppressions.cc
@@ -280,9 +280,6 @@ // https://crbug.com/539315 "race:MojoCreateMessagePipe\n" -// http://crbug.com/559117 -"race:base::trace_event::TraceConfig::AsConvertableToTraceFormat\n" - // https://crbug.com/569682 "race:blink::ThreadState::visitStackRoots\n"
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn index cc14b819..700b2119 100644 --- a/chrome/BUILD.gn +++ b/chrome/BUILD.gn
@@ -8,17 +8,12 @@ import("//build/config/locales.gni") import("//build/config/sanitizers/sanitizers.gni") import("//build/config/ui.gni") +import("//build/config/win/console_app.gni") import("//build/config/win/manifest.gni") import("//chrome/chrome_repack_locales.gni") import("//chrome/version.gni") declare_args() { - # If true, builds as a console app (rather than a windowed app), which allows - # logging to be printed to the user. This will cause a terminal window to pop - # up when Chrome is not run from the command line, so should only be used for - # development. Only has an effect on Windows builds. - win_console_app = false - # Specify the current PGO phase, only used for the Windows MSVS build. Here's # the different values that can be used: # 0 : Means that PGO is turned off. @@ -58,12 +53,6 @@ ":chrome_initial", ] } - - # The AddressSanitizer build should be a console program as it prints out - # stuff on stderr. - if (is_asan) { - win_console_app = true - } } if (!is_android) { @@ -148,6 +137,7 @@ "//components/crash/content/app", "//components/crash/core/common", "//components/flags_ui:switches", + "//components/startup_metric_utils/common", "//content:sandbox_helper_win", "//content/public/common:static_switches", "//crypto", @@ -421,7 +411,15 @@ configs += [ "//build/config/win:no_incremental_linking" ] } if (chrome_pgo_phase > 0) { - configs += [ "//build/config/compiler:optimize_max" ] + cflags += [ + "/GL", # Whole program optimization. + + # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds. + # Probably anything that this would catch that wouldn't be caught in + # a normal build isn't going to actually be a bug, so the + # incremental value of C4702 for PGO builds is likely very small. + "/wd4702", + ] } if (chrome_pgo_phase == 1) { ldflags = [
diff --git a/chrome/VERSION b/chrome/VERSION index baf4fa2..e08d3eae 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=50 MINOR=0 -BUILD=2625 +BUILD=2626 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index 335cdddb..f2f5fe22 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -258,6 +258,7 @@ java_files = [ "junit/src/org/chromium/chrome/browser/SSLClientCertificateRequestTest.java", "junit/src/org/chromium/chrome/browser/crash/LogcatExtractionCallableTest.java", + "junit/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtilsTest.java", "junit/src/org/chromium/chrome/browser/externalauth/ExternalAuthUtilsTest.java", "junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java", "junit/src/org/chromium/chrome/browser/gcore/GoogleApiClientConnectionHelperTest.java", @@ -279,7 +280,9 @@ "//base:base_java", "//base:base_java_test_support", "//base:base_junit_test_support", + "//components/bookmarks/common/android:bookmarks_java", "//components/invalidation/impl:java", + "//content/public/android:content_java", "//sync:sync_java_test_support", "//sync/android:sync_java", "//third_party/android_tools:android_support_v7_mediarouter_java",
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml index 73d3dbe..b21f383 100644 --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml
@@ -642,7 +642,8 @@ android:exported="false" /> {% endfor %} - <receiver android:name="org.chromium.chrome.browser.download.OpenDownloadReceiver"> + <receiver android:name="org.chromium.chrome.browser.download.DownloadBroadcastReceiver" + android:exported="false"> <intent-filter> <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/> </intent-filter>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java index ac8e02b..79976e2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/DeferredStartupHandler.java
@@ -17,7 +17,6 @@ import org.chromium.chrome.browser.bookmarkswidget.BookmarkThumbnailWidgetProviderBase; import org.chromium.chrome.browser.crash.CrashFileManager; import org.chromium.chrome.browser.crash.MinidumpUploadService; -import org.chromium.chrome.browser.download.DownloadManagerService; import org.chromium.chrome.browser.media.MediaCaptureNotificationService; import org.chromium.chrome.browser.partnerbookmarks.PartnerBookmarksShim; import org.chromium.chrome.browser.physicalweb.PhysicalWeb; @@ -107,9 +106,6 @@ // Starts syncing with GSA. application.createGsaHelper().startSync(); - DownloadManagerService.getDownloadManagerService(application) - .clearPendingDownloadNotifications(); - application.initializeSharedClasses(); ShareHelper.clearSharedImages(application);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java new file mode 100644 index 0000000..65d4f3c1 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastReceiver.java
@@ -0,0 +1,83 @@ +// 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.download; + +import android.app.DownloadManager; +import android.content.ActivityNotFoundException; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; + +/** + * This {@link BroadcastReceiver} handles clicks to download notifications and their action buttons. + * Clicking on an in-progress or failed download will open the download manager. Clicking on + * a complete, successful download will open the file. Clicking on the resume button of a paused + * download will relaunch the browser process and try to resume the download from where it is + * stopped. + */ +public class DownloadBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(final Context context, Intent intent) { + String action = intent.getAction(); + switch (action) { + case DownloadManager.ACTION_NOTIFICATION_CLICKED: + openDownload(context, intent); + break; + case DownloadNotificationService.ACTION_DOWNLOAD_RESUME: + resumeDownload(context, intent); + break; + default: + break; + } + } + + /** + * Called to open a given download item that is downloaded by the android DownloadManager. + * @param context Context of the receiver. + * @param intent Intent from the android DownloadManager. + */ + private void openDownload(final Context context, Intent intent) { + long ids[] = + intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); + if (ids == null || ids.length == 0) { + DownloadManagerService.openDownloadsPage(context); + return; + } + long id = ids[0]; + DownloadManager manager = + (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + Uri uri = manager.getUriForDownloadedFile(id); + if (uri == null) { + // Open the downloads page + DownloadManagerService.openDownloadsPage(context); + } else { + Intent launchIntent = new Intent(Intent.ACTION_VIEW); + launchIntent.setDataAndType(uri, manager.getMimeTypeForDownloadedFile(id)); + launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + context.startActivity(launchIntent); + } catch (ActivityNotFoundException e) { + DownloadManagerService.openDownloadsPage(context); + } + } + } + + /** + * Called to handle download resumption. This will call the DownloadNotificationService + * to start the browser process asynchronously, and resume the download afterwards. + * @param context Context of the receiver. + * @param intent Intent from the android DownloadManager. + */ + private void resumeDownload(final Context context, Intent intent) { + if (DownloadNotificationService.isDownloadResumptionIntent(intent)) { + Intent launchIntent = new Intent(intent); + launchIntent.setComponent(new ComponentName( + context.getPackageName(), DownloadNotificationService.class.getName())); + context.startService(launchIntent); + } + } +} \ No newline at end of file
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 60fd6c0a..d6c3505d7 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
@@ -24,6 +24,7 @@ import org.chromium.base.Log; import org.chromium.base.ThreadUtils; import org.chromium.base.VisibleForTesting; +import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.SuppressFBWarnings; import org.chromium.chrome.R; import org.chromium.chrome.browser.IntentHandler; @@ -91,6 +92,7 @@ new LongSparseArray<DownloadInfo>(); private OMADownloadHandler mOMADownloadHandler; private DownloadSnackbarController mDownloadSnackbarController; + private long mNativeDownloadManagerService; /** * Enum representing status of a download. @@ -156,6 +158,50 @@ } /** + * Class representing a pending notification entry. + */ + @VisibleForTesting + static class PendingNotification { + public final int downloadId; + public final String fileName; + public final boolean isResumable; + + PendingNotification(int downloadId, String fileName, boolean isResumable) { + this.downloadId = downloadId; + this.fileName = fileName; + this.isResumable = isResumable; + } + + /** + * Parse the pending notification from a String object in SharedPrefs. + * + * @param notification String containing the notification ID, file name and whether it is + * resumable. + * @return a PendingNotification object. + */ + static PendingNotification parseFromString(String notification) { + String[] values = notification.split(",", 3); + if (values.length == 3) { + try { + int id = Integer.parseInt(values[0]); + boolean isResumable = "1".equals(values[1]); + return new PendingNotification(id, values[2], isResumable); + } catch (NumberFormatException nfe) { + Log.w(TAG, "Exception while parsing pending download:" + notification); + } + } + return new PendingNotification(-1, "", false); + } + + /** + * Generate a string for the PendingNotification instance to be inserted into SharedPrefs. + */ + String getNotificationString() { + return downloadId + "," + (isResumable ? "1" : "0") + "," + fileName; + } + } + + /** * Creates DownloadManagerService. */ @SuppressFBWarnings("LI_LAZY_INIT") // Findbugs doesn't see this is only UI thread. @@ -201,6 +247,16 @@ mIsUIUpdateScheduled = new AtomicBoolean(false); mOMADownloadHandler = new OMADownloadHandler(context); mDownloadSnackbarController = new DownloadSnackbarController(context); + clearPendingDownloadNotifications(); + // Note that this technically leaks the native object, however, DownloadManagerService + // is a singleton that lives forever and there's no clean shutdown of Chrome on Android. + init(); + } + + @VisibleForTesting + protected void init() { + mNativeDownloadManagerService = nativeInit(); + DownloadController.setDownloadNotificationService(this); } @Override @@ -229,15 +285,9 @@ if (mSharedPrefs.contains(DOWNLOAD_NOTIFICATION_IDS)) { mSharedPrefs.edit().remove(DOWNLOAD_NOTIFICATION_IDS).apply(); } - List<Pair<Integer, String>> notifications = - parseDownloadNotificationsFromSharedPrefs(mSharedPrefs); - for (Pair<Integer, String> notification : notifications) { - if (notification.first > 0) { - mDownloadNotifier.cancelNotification(notification.first); - Log.w(TAG, "Download failed: Cleared download id:" + notification.first); - } + if (mSharedPrefs.contains(PENDING_DOWNLOAD_NOTIFICATIONS)) { + mSharedPrefs.edit().remove(PENDING_DOWNLOAD_NOTIFICATIONS).apply(); } - mSharedPrefs.edit().remove(PENDING_DOWNLOAD_NOTIFICATIONS).apply(); if (mSharedPrefs.contains(PENDING_OMA_DOWNLOADS)) { Set<String> omaDownloads = getStoredDownloadInfo(mSharedPrefs, PENDING_OMA_DOWNLOADS); for (String omaDownload : omaDownloads) { @@ -252,14 +302,14 @@ * @param sharedPrefs SharedPreferences that contains the download notifications. * @return a list of parsed notifications. */ - static List<Pair<Integer, String>> parseDownloadNotificationsFromSharedPrefs( + static List<PendingNotification> parseDownloadNotificationsFromSharedPrefs( SharedPreferences sharedPrefs) { - List<Pair<Integer, String>> result = new ArrayList<Pair<Integer, String>>(); + List<PendingNotification> result = new ArrayList<PendingNotification>(); if (sharedPrefs.contains(DownloadManagerService.PENDING_DOWNLOAD_NOTIFICATIONS)) { Set<String> pendingDownloads = DownloadManagerService.getStoredDownloadInfo( sharedPrefs, DownloadManagerService.PENDING_DOWNLOAD_NOTIFICATIONS); for (String download : pendingDownloads) { - result.add(DownloadManagerService.parseNotificationString(download)); + result.add(PendingNotification.parseFromString(download)); } } return result; @@ -354,36 +404,6 @@ } /** - * Parse the notification ID from a String object in SharedPrefs. - * - * @param notification String containing the notification ID and file name. - * @return a pair of notification ID and file name. - */ - static Pair<Integer, String> parseNotificationString(String notification) { - int index = notification.indexOf(","); - if (index <= 0) return Pair.create(-1, ""); - try { - int id = Integer.parseInt(notification.substring(0, index)); - return Pair.create(id, notification.substring(index + 1)); - } catch (NumberFormatException nfe) { - Log.w(TAG, "Exception while parsing pending download:" + notification); - return Pair.create(-1, ""); - } - } - - /** - * Generate a string for the download Id and file name pair to be - * inserted into SharedPrefs. - * - * @param downloadId ID of the download. - * @param fileName Name of the file to be downloaded. - * @return notification string containing the notification ID and file name. - */ - static String getNotificationString(int downloadId, String fileName) { - return downloadId + "," + fileName; - } - - /** * Broadcast that a download was successful. * @param downloadInfo info about the download. */ @@ -408,8 +428,8 @@ Set<String> pendingDownloads = getStoredDownloadInfo(mSharedPrefs, PENDING_DOWNLOAD_NOTIFICATIONS); for (String download : pendingDownloads) { - Pair<Integer, String> notification = parseNotificationString(download); - if (notification.first == downloadId) { + PendingNotification notification = PendingNotification.parseFromString(download); + if (notification.downloadId == downloadId) { pendingDownloads.remove(download); storeDownloadInfo(PENDING_DOWNLOAD_NOTIFICATIONS, pendingDownloads); break; @@ -418,15 +438,14 @@ } /** - * Add a pending download to SharedPrefs, the string consists of both the download ID - * and file name. - * @param downloadId ID to be stored. - * @param fileName Name of the file, used for notifications. + * Add a pending download to SharedPrefs, the string consists of the download ID, file name and + * whether it is resumable. + * @param pendingNotification Pending download entry. */ - private void addPendingDownloadToSharedPrefs(int downloadId, String fileName) { + private void addPendingDownloadToSharedPrefs(PendingNotification pendingNotification) { Set<String> pendingDownloads = getStoredDownloadInfo(mSharedPrefs, PENDING_DOWNLOAD_NOTIFICATIONS); - pendingDownloads.add(getNotificationString(downloadId, fileName)); + pendingDownloads.add(pendingNotification.getNotificationString()); storeDownloadInfo(PENDING_DOWNLOAD_NOTIFICATIONS, pendingDownloads); } @@ -659,7 +678,8 @@ if (status == DownloadStatus.IN_PROGRESS) { // A new in-progress download, add an entry to shared prefs to make sure // to clear the notification. - addPendingDownloadToSharedPrefs(downloadId, downloadInfo.getFileName()); + addPendingDownloadToSharedPrefs(new PendingNotification( + downloadId, downloadInfo.getFileName(), downloadInfo.isResumable())); } mDownloadProgressMap.putIfAbsent(downloadId, progress); } else { @@ -1071,4 +1091,30 @@ Log.e(TAG, "Cannot find Downloads app", e); } } + + /** + * Called to resume a paused download. + * @param downloadId Id of the download. + */ + void resumeDownload(int downloadId, String fileName) { + nativeResumeDownload(mNativeDownloadManagerService, downloadId, fileName); + mDownloadNotifier.notifyDownloadProgress( + new DownloadInfo.Builder() + .setDownloadId(downloadId) + .setFileName(fileName) + .setPercentCompleted( + DownloadNotificationService.INVALID_DOWNLOAD_PERCENTAGE) + .build(), + 0); + } + + @CalledByNative + void onResumptionFailed(int downloadId, String fileName) { + mDownloadNotifier.notifyDownloadFailed( + new DownloadInfo.Builder().setDownloadId(downloadId).setFileName(fileName).build()); + } + + private native long nativeInit(); + private native void nativeResumeDownload( + long nativeDownloadManagerService, int downloadId, String fileName); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java index 31ed6497..0690a7e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java
@@ -8,6 +8,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; @@ -15,10 +16,16 @@ import android.os.IBinder; import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; -import android.util.Pair; +import org.chromium.base.Log; import org.chromium.base.VisibleForTesting; +import org.chromium.base.library_loader.ProcessInitException; import org.chromium.chrome.R; +import org.chromium.chrome.browser.ChromeApplication; +import org.chromium.chrome.browser.init.BrowserParts; +import org.chromium.chrome.browser.init.ChromeBrowserInitializer; +import org.chromium.chrome.browser.init.EmptyBrowserParts; +import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.ui.base.LocalizationUtils; import java.text.NumberFormat; @@ -30,8 +37,13 @@ * Chrome gets killed. */ public class DownloadNotificationService extends Service { + static final String EXTRA_DOWNLOAD_ID = "DownloadId"; + static final String EXTRA_DOWNLOAD_FILE_NAME = "DownloadFileName"; + static final String ACTION_DOWNLOAD_RESUME = + "org.chromium.chrome.browser.download.DOWNLOAD_RESUME"; + static final int INVALID_DOWNLOAD_PERCENTAGE = -1; private static final String NOTIFICATION_NAMESPACE = "DownloadNotificationService"; - private static final int INVALID_DOWNLOAD_PERCENTAGE = -1; + private static final String TAG = "DownloadNotification"; private final IBinder mBinder = new LocalBinder(); private NotificationManager mNotificationManager; private Context mContext; @@ -75,6 +87,29 @@ @Override public int onStartCommand(Intent intent, int flags, int startId) { + if (isDownloadResumptionIntent(intent)) { + final int downloadId = IntentUtils.safeGetIntExtra( + intent, DownloadNotificationService.EXTRA_DOWNLOAD_ID, -1); + final String fileName = IntentUtils.safeGetStringExtra( + intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_NAME); + BrowserParts parts = new EmptyBrowserParts() { + @Override + public void finishNativeInitialization() { + DownloadManagerService service = + DownloadManagerService.getDownloadManagerService( + getApplicationContext()); + service.resumeDownload(downloadId, fileName); + } + }; + try { + ChromeBrowserInitializer.getInstance(mContext).handlePreNativeStartup(parts); + ChromeBrowserInitializer.getInstance(mContext).handlePostNativeStartup(true, parts); + } catch (ProcessInitException e) { + Log.e(TAG, "Unable to load native library.", e); + ChromeApplication.reportStartupErrorAndExit(e); + } + } + // This should restart the service after Chrome gets killed. However, this // doesn't work on Android 4.4.2. return START_STICKY; @@ -123,12 +158,25 @@ * Change a download notification to paused state. * @param downloadId ID of the download. * @param fileName File name of the download. + * @param isResumable whether download is resumable. */ - public void notifyDownloadPaused(int downloadId, String fileName) { + public void notifyDownloadPaused(int downloadId, String fileName, boolean isResumable) { NotificationCompat.Builder builder = buildNotification( android.R.drawable.ic_media_pause, fileName, mContext.getResources().getString(R.string.download_notification_paused)); + if (isResumable) { + ComponentName component = new ComponentName( + mContext.getPackageName(), DownloadBroadcastReceiver.class.getName()); + Intent intent = new Intent(ACTION_DOWNLOAD_RESUME); + intent.setComponent(component); + intent.putExtra(EXTRA_DOWNLOAD_ID, downloadId); + intent.putExtra(EXTRA_DOWNLOAD_FILE_NAME, fileName); + builder.addAction(android.R.drawable.stat_sys_download_done, + mContext.getResources().getString(R.string.download_notification_resume_button), + PendingIntent.getBroadcast( + mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)); + } updateNotification(downloadId, builder.build()); } @@ -171,11 +219,12 @@ void pauseAllDownloads() { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(mContext); - List<Pair<Integer, String>> notifications = + List<DownloadManagerService.PendingNotification> notifications = DownloadManagerService.parseDownloadNotificationsFromSharedPrefs(sharedPrefs); - for (Pair<Integer, String> notification : notifications) { - if (notification.first > 0) { - notifyDownloadPaused(notification.first, notification.second); + for (DownloadManagerService.PendingNotification notification : notifications) { + if (notification.downloadId > 0) { + notifyDownloadPaused( + notification.downloadId, notification.fileName, notification.isResumable); } } } @@ -207,4 +256,23 @@ void updateNotification(int id, Notification notification) { mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification); } + + /** + * Checks if an intent is about to resume a download. + * @param intent An intent to validate. + * @return true if the intent is for download resumption, or false otherwise. + */ + static boolean isDownloadResumptionIntent(Intent intent) { + if (!intent.hasExtra(DownloadNotificationService.EXTRA_DOWNLOAD_ID) + || !intent.hasExtra(DownloadNotificationService.EXTRA_DOWNLOAD_FILE_NAME)) { + return false; + } + final int downloadId = IntentUtils.safeGetIntExtra( + intent, DownloadNotificationService.EXTRA_DOWNLOAD_ID, -1); + if (downloadId == -1) return false; + final String fileName = IntentUtils.safeGetStringExtra( + intent, DownloadNotificationService.EXTRA_DOWNLOAD_FILE_NAME); + if (fileName == null) return false; + return true; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/OpenDownloadReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/download/OpenDownloadReceiver.java deleted file mode 100644 index b6ee223d..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/OpenDownloadReceiver.java +++ /dev/null
@@ -1,52 +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. - -package org.chromium.chrome.browser.download; - -import android.app.DownloadManager; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; - -/** - * This {@link BroadcastReceiver} handles clicks to notifications that - * downloads from the browser are in progress/complete. Clicking on an - * in-progress or failed download will open the download manager. Clicking on - * a complete, successful download will open the file. - */ -public class OpenDownloadReceiver extends BroadcastReceiver { - @Override - public void onReceive(final Context context, Intent intent) { - String action = intent.getAction(); - if (!DownloadManager.ACTION_NOTIFICATION_CLICKED.equals(action)) { - DownloadManagerService.openDownloadsPage(context); - return; - } - long ids[] = intent.getLongArrayExtra( - DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); - if (ids == null || ids.length == 0) { - DownloadManagerService.openDownloadsPage(context); - return; - } - long id = ids[0]; - DownloadManager manager = (DownloadManager) context.getSystemService( - Context.DOWNLOAD_SERVICE); - Uri uri = manager.getUriForDownloadedFile(id); - if (uri == null) { - // Open the downloads page - DownloadManagerService.openDownloadsPage(context); - } else { - Intent launchIntent = new Intent(Intent.ACTION_VIEW); - launchIntent.setDataAndType(uri, manager.getMimeTypeForDownloadedFile(id)); - launchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - context.startActivity(launchIntent); - } catch (ActivityNotFoundException e) { - DownloadManagerService.openDownloadsPage(context); - } - } - } -} \ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java index f3692f7..34af58f4 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java
@@ -60,8 +60,11 @@ public static void addOrEditBookmark(long idToAdd, EnhancedBookmarksModel bookmarkModel, Tab tab, SnackbarManager snackbarManager, Activity activity) { if (idToAdd != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID) { + // See if the Tab's contents should be saved or not. + WebContents webContentsToSave = null; + if (!shouldSkipSavingTabOffline(tab)) webContentsToSave = tab.getWebContents(); startEditActivity(activity, new BookmarkId(idToAdd, BookmarkType.NORMAL), - tab.getWebContents()); + webContentsToSave); return; } @@ -348,6 +351,9 @@ /** * Starts an {@link EnhancedBookmarkEditActivity} for the given {@link BookmarkId}. + * If the given {@link WebContents} is null, an option to visit the page is shown + * as opposed to showing an option to directly save the page + * (only if offline pages are enabled). */ public static void startEditActivity( Context context, BookmarkId bookmarkId, WebContents webContents) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java index 6ba26366..d5a7ec5 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunSignInProcessor.java
@@ -121,7 +121,7 @@ */ private static void openSyncSettings(Activity activity) { if (ProfileSyncService.get() == null) return; - assert !ProfileSyncService.get().hasSyncSetupCompleted(); + assert !ProfileSyncService.get().isFirstSetupComplete(); String accountName = ChromeSigninController.get(activity).getSignedInAccountName(); if (TextUtils.isEmpty(accountName)) return; Intent intent = PreferencesLauncher.createIntentForSettingsPage(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java index 3a2df20..f05d6ae 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/AbstractMediaRouteController.java
@@ -115,11 +115,6 @@ } @Override - public void onRouteAdded(MediaRouter router, RouteInfo route) { - onRouteAddedEvent(router, route); - } - - @Override public void onRouteChanged(MediaRouter router, RouteInfo route) { // We only care about changes to the current route. if (!route.equals(getCurrentRoute())) return; @@ -164,7 +159,6 @@ private RouteInfo mCurrentRoute; private boolean mDebug; private final DeviceDiscoveryCallback mDeviceDiscoveryCallback;; - private String mDeviceId; private final DeviceSelectionCallback mDeviceSelectionCallback; private final Handler mHandler; @@ -260,7 +254,6 @@ if (getMediaRouter() != null) { getMediaRouter().getDefaultRoute().select(); registerRoute(getMediaRouter().getDefaultRoute()); - RemotePlaybackSettings.setDeviceId(getContext(), null); } } @@ -278,10 +271,6 @@ return mCurrentRoute; } - protected final String getDeviceId() { - return mDeviceId; - } - protected final Handler getHandler() { return mHandler; } @@ -372,9 +361,11 @@ resume(); } - protected abstract void onRouteAddedEvent(MediaRouter router, RouteInfo route); + protected void onRouteAddedEvent(MediaRouter router, RouteInfo route) { + }; - // TODO: Merge with onRouteSelected(). Needs two sided patch for downstream implementations + // TODO(aberent): Merge with onRouteSelected(). Needs two sided patch for downstream + // implementations protected void onRouteSelectedEvent(MediaRouter router, RouteInfo route) { } @@ -406,13 +397,7 @@ mCurrentRoute = route; if (route != null) { - setDeviceId(route.getId()); - if (mDebug) Log.d(TAG, "Selected route " + getDeviceId()); - if (!route.isDefault()) { - RemotePlaybackSettings.setDeviceId(getContext(), getDeviceId()); - } - } else { - RemotePlaybackSettings.setDeviceId(getContext(), null); + if (mDebug) Log.d(TAG, "Selected route " + route.getId()); } } @@ -452,10 +437,6 @@ if (mMediaStateListener != null) mMediaStateListener.onError(); } - protected void setDeviceId(String mDeviceId) { - this.mDeviceId = mDeviceId; - } - @Override public void setMediaStateListener(MediaStateListener mediaStateListener) { mMediaStateListener = mediaStateListener; @@ -568,22 +549,12 @@ if (mMediaStateListener != null) mMediaStateListener.onPlaybackStateChanged(mPlaybackState); if (oldState != mPlaybackState) { - // We need to persist our state in case we get killed. - RemotePlaybackSettings.setLastVideoState(getContext(), mPlaybackState.name()); switch (mPlaybackState) { case PLAYING: - RemotePlaybackSettings.setRemainingTime(getContext(), - getDuration() - getPosition()); - RemotePlaybackSettings.setLastPlayedTime(getContext(), - System.currentTimeMillis()); - RemotePlaybackSettings.setShouldReconnectToRemote(getContext(), - !mCurrentRoute.isDefault()); onCasting(); break; case PAUSED: - RemotePlaybackSettings.setShouldReconnectToRemote(getContext(), - !mCurrentRoute.isDefault()); onCasting(); break; case FINISHED: @@ -610,13 +581,20 @@ @Override public Bitmap getPoster() { - if (mMediaStateListener == null) return null; - return mMediaStateListener.getPosterBitmap(); + if (getMediaStateListener() == null) return null; + return getMediaStateListener().getPosterBitmap(); } + /** + * Called to prepare the remote playback asyncronously. onPrepared() of the current remote media + * player object is called when the player is ready. + * + * @param startPositionMillis indicates where in the stream to start playing + */ + protected abstract void prepareAsync(String frameUrl, long startPositionMillis); + // TODO(aberent): Temp to change args while avoiding need for two sided patch for YT. - @Override - public void setDataSource(Uri uri, String cookies, String userAgent) { + void setDataSource(Uri uri, String cookies, String userAgent) { setDataSource(uri, cookies); }; @@ -628,4 +606,14 @@ * @param cookies */ public void setDataSource(Uri uri, String cookies) {}; + + protected boolean reconnectAnyExistingRoute() { + // Temp version to avoid two sided patch while removing + return false; + }; + + @Override + public String getUriPlaying() { + return null; + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java index 4ed654c..62cf4437 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/DefaultMediaRouteController.java
@@ -50,9 +50,6 @@ * remotely meaning that we don't have to start the session but to replace the current video with * the new one * - * - the reconnect: if Clank crashes, we need to try to reconnect to the existing session and - * continue controlling the currently playing video. - * * Casting the first video takes three intents sent to the selected media route: * ACTION_START_SESSION, ACTION_SYNC_STATUS and ACTION_PLAY. The first one is sent before anything * else. We get the session id from the result bundle of the intent but need to wait until the @@ -60,19 +57,8 @@ * intent to update the media item status and pass the PendingIntent for the media item status * events to the Cast MRP. Finally we send the video URL via the ACTION_PLAY intent. * - * Casting the second video should only take one ACTION_PLAY intent if the session is still active. - * Otherwise, the scenario is the same as for the first video. However, due to the crbug.com/336188 - * we need to restart the session for each ACTION_PLAY so we go through the same process as above. - * - * In order to reconnect, we need to programmatically select the previously selected media route. - * To do this we send an ACTION_START_SESSION with the old session ID. This is not clearly - * documented in the Android documentation, but seems to only succeed if the session still exists. - * Otherwise we need to start a new session. - * - * Note that, if the Chrome cast notification restarts following a crash, instances of this class - * may exist before the C++ library has been loaded. As such this class should avoid using anything - * that might use the C++ library (almost anything else in Chrome) or check that the library is - * loaded before using them (as it does for recording UMA statistics). + * Casting the second video to the same target device should only take one ACTION_PLAY intent if + * the session is still active. Otherwise, the scenario is the same as for the first video. */ public class DefaultMediaRouteController extends AbstractMediaRouteController { @@ -104,9 +90,7 @@ private BroadcastReceiver mSessionStatusBroadcastReceiver; private PendingIntent mMediaStatusUpdateIntent; private BroadcastReceiver mMediaStatusBroadcastReceiver; - private boolean mReconnecting = false; - private Uri mVideoUriToStart; private String mPreferredTitle; private long mStartPositionMillis; @@ -228,86 +212,6 @@ } @Override - public boolean reconnectAnyExistingRoute() { - String deviceId = RemotePlaybackSettings.getDeviceId(getContext()); - RouteInfo defaultRoute = getMediaRouter().getDefaultRoute(); - if (deviceId == null || deviceId.equals(defaultRoute.getId()) || !shouldReconnect()) { - RemotePlaybackSettings.setShouldReconnectToRemote(getContext(), false); - return false; - } - mReconnecting = true; - selectDevice(deviceId); - getHandler().postDelayed(new Runnable() { - @Override - public void run() { - if (mReconnecting) { - Log.d(TAG, "Reconnection timed out"); - // We have been trying to reconnect for too long. Give up and save battery. - mReconnecting = false; - release(); - } - } - }, CONNECTION_FAILURE_NOTIFICATION_DELAY_MS); - return true; - } - - private boolean shouldReconnect() { - if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_CAST_RECONNECTION)) { - if (mDebug) Log.d(TAG, "Cast reconnection disabled"); - return false; - } - boolean reconnect = false; - if (RemotePlaybackSettings.getShouldReconnectToRemote(getContext())) { - String lastState = RemotePlaybackSettings.getLastVideoState(getContext()); - if (lastState != null) { - PlayerState state = PlayerState.valueOf(lastState); - if (state == PlayerState.PLAYING || state == PlayerState.LOADING) { - // If we were playing when we got killed, check the time to - // see if it's still - // plausible that the remote video is playing currently - long remainingPlaytime = RemotePlaybackSettings.getRemainingTime(getContext()); - long lastPlayedTime = RemotePlaybackSettings.getLastPlayedTime(getContext()); - long currentTime = System.currentTimeMillis(); - if (currentTime < lastPlayedTime + remainingPlaytime) { - reconnect = true; - } - } else if (state == PlayerState.PAUSED) { - reconnect = true; - } - } - } - if (mDebug) Log.d(TAG, "shouldReconnect returning: " + reconnect); - return reconnect; - } - - /** - * Tries to select a device with the given device ID. The device ID is cached so that if the - * route does not exist yet, we will connect to it as soon as it comes back up again - * - * @param deviceId the ID of the device to connect to - */ - private void selectDevice(String deviceId) { - if (deviceId == null) { - release(); - return; - } - - setDeviceId(deviceId); - - if (mDebug) Log.d(TAG, "Trying to select " + getDeviceId()); - - // See if we can select the device at this point. - if (getMediaRouter() != null) { - for (MediaRouter.RouteInfo route : getMediaRouter().getRoutes()) { - if (deviceId.equals(route.getId())) { - route.select(); - break; - } - } - } - } - - @Override public void resume() { if (mCurrentItemId == null) return; @@ -360,40 +264,27 @@ /** * Plays the given Uri on the currently selected player. This will replace any currently playing * video - * - * @param videoUri Uri of the video to play * @param preferredTitle the preferred title of the current playback session to display * @param startPositionMillis from which to start playing. */ - private void playUri(final Uri videoUri, - @Nullable final String preferredTitle, final long startPositionMillis) { - - RecordCastAction.castMediaType(MediaUrlResolver.getMediaType(videoUri.toString())); + private void playUri(@Nullable final String preferredTitle, final long startPositionMillis) { + RecordCastAction.castMediaType(MediaUrlResolver.getMediaType(mLocalVideoUri.toString())); installBroadcastReceivers(); - // Check if we are reconnecting or have reconnected and are playing the same video - if ((mReconnecting || mCurrentSessionId != null) - && videoUri.toString().equals(RemotePlaybackSettings.getUriPlaying(getContext()))) { - return; - } - // If the session is already started (meaning we are casting a video already), we simply // load the new URL with one ACTION_PLAY intent. if (mCurrentSessionId != null) { - if (mDebug) Log.d(TAG, "Playing a new url: " + videoUri); - - RemotePlaybackSettings.setUriPlaying(getContext(), videoUri.toString()); + if (mDebug) Log.d(TAG, "Playing a new url: " + mLocalVideoUri); // We keep the same session so only clear the playing item status. clearItemState(); - startPlayback(videoUri, preferredTitle, startPositionMillis); + startPlayback(preferredTitle, startPositionMillis); return; } - RemotePlaybackSettings.setPlayerInUse(getContext(), getCastReceiverId()); if (mDebug) { Log.d(TAG, "Sending stream to app: " + getCastReceiverId()); - Log.d(TAG, "Url: " + videoUri); + Log.d(TAG, "Url: " + mLocalVideoUri); } startSession(true, null, new ResultBundleHandler() { @@ -401,8 +292,6 @@ public void onResult(Bundle data) { configureNewSession(data); - mVideoUriToStart = videoUri; - RemotePlaybackSettings.setUriPlaying(getContext(), videoUri.toString()); mPreferredTitle = preferredTitle; mStartPositionMillis = startPositionMillis; // Make sure we get a session status. If the session becomes active @@ -463,12 +352,12 @@ }); } - private void startPlayback(final Uri videoUri, @Nullable final String preferredTitle, - final long startPositionMillis) { + private void startPlayback( + @Nullable final String preferredTitle, final long startPositionMillis) { setUnprepared(); Intent intent = new Intent(MediaControlIntent.ACTION_PLAY); intent.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK); - intent.setDataAndType(videoUri, MIME_TYPE); + intent.setDataAndType(mLocalVideoUri, MIME_TYPE); intent.putExtra(MediaControlIntent.EXTRA_SESSION_ID, mCurrentSessionId); intent.putExtra(MediaControlIntent.EXTRA_ITEM_STATUS_UPDATE_RECEIVER, mMediaStatusUpdateIntent); @@ -552,19 +441,11 @@ if (getMediaStateListener() != null) getMediaStateListener().onRouteUnselected(); setMediaStateListener(null); - stopAndDisconnect(); - } - - /** - * Stop the current remote playback and release all associated resources. Resources will be - * released even if the stop operation fails. - */ - private void stopAndDisconnect() { if (mediaRouterInitializationFailed()) return; if (mCurrentSessionId == null) { // This can happen if we disconnect after a failure (because the // media could not be casted). - disconnect(true); + disconnect(); return; } @@ -605,28 +486,24 @@ } RecordCastAction.castEndedTimeRemaining(mStreamDuration, mStreamDuration - getPosition()); - disconnect(true); + disconnect(); } @Override public void onError(String message, Bundle data) { - disconnect(true); + disconnect(); } }); } + /** * Disconnect from the remote screen without stopping the media playing. use release() for * disconnect + stop. - * - * @param finishedWithRoute true if finished with route and remote device, false if just - * shutting down Chrome. */ - private void disconnect(boolean finishedWithRoute) { - if (finishedWithRoute) { - clearStreamState(); - clearMediaRoute(); - } + private void disconnect() { + clearStreamState(); + clearMediaRoute(); if (mSessionStatusBroadcastReceiver != null) { getContext().unregisterReceiver(mSessionStatusBroadcastReceiver); @@ -643,16 +520,6 @@ } @Override - protected void onRouteAddedEvent(MediaRouter router, RouteInfo route) { - if (mDebug) Log.d(TAG, "Added route " + route); - if (getDeviceId() != null && getDeviceId().equals(route.getId())) { - // This is the route we are waiting to connect to, select it. - if (mDebug) Log.d(TAG, "Selecting Added Device " + route.getName()); - route.select(); - } - } - - @Override protected void onRouteSelectedEvent(MediaRouter router, RouteInfo route) { if (mDebug) Log.d(TAG, "Selected route " + route); if (!route.isSelected()) return; @@ -667,33 +534,11 @@ return; } - registerRoute(route); - if (shouldReconnect()) { - startSession(false, RemotePlaybackSettings.getSessionId(getContext()), - new ResultBundleHandler() { - @Override - public void onResult(Bundle data) { - configureNewSession(data); - setUnprepared(); - mReconnecting = false; - // Make sure we get a session status. If the session becomes active - // immediately then the broadcast session status can arrive before we - // have the session id, so this ensures we get it whatever happens. - getSessionStatus(mCurrentSessionId); - } - - @Override - public void onError(String message, Bundle data) { - // Ignore errors, the connection sometimes is bouncy on reconnection, - // and the reconnection timer is still running so will tidy up if - // we never manage to connect. - } - }); - } else { + if (route != getCurrentRoute()) { + registerRoute(route); clearStreamState(); - mReconnecting = false; - mLastKnownStreamPosition = 0; } + mLastKnownStreamPosition = 0; notifyRouteSelected(route); } @@ -763,24 +608,16 @@ */ protected void onActivitiesDestroyed() { ApplicationStatus.unregisterApplicationStateListener(mApplicationStateListener); - // It is important to not clear the stream state here to let Chrome - // reconnect to a session upon startup. - disconnect(false); + disconnect(); } /** * Clear the session and the currently playing item (if any). */ protected void clearStreamState() { - mVideoUriToStart = null; mLocalVideoUri = null; mCurrentSessionId = null; clearItemState(); - - if (getContext() != null) { - RemotePlaybackSettings.setShouldReconnectToRemote(getContext(), false); - RemotePlaybackSettings.setUriPlaying(getContext(), null); - } } @Override @@ -822,9 +659,8 @@ @Override public void onResult(Bundle data) { processMediaStatusBundle(data); - if (mVideoUriToStart != null) { - startPlayback(mVideoUriToStart, mPreferredTitle, mStartPositionMillis); - mVideoUriToStart = null; + if (mLocalVideoUri != null) { + startPlayback(mPreferredTitle, mStartPositionMillis); } } @@ -1018,7 +854,7 @@ } @Override - public void setDataSource(Uri uri, String cookies, String userAgent) { + protected void setDataSource(Uri uri, String cookies, String userAgent) { if (mDebug) Log.d(TAG, "setDataSource called, uri = " + uri); mLocalVideoUri = uri; mLocalVideoCookies = cookies; @@ -1026,7 +862,7 @@ } @Override - public void prepareAsync(String frameUrl, long startPositionMillis) { + protected void prepareAsync(String frameUrl, long startPositionMillis) { if (mDebug) { Log.d(TAG, "prepareAsync called, mLocalVideoUri = " + mLocalVideoUri + ", pos = " + startPositionMillis); @@ -1049,7 +885,7 @@ private void playMedia() { String title = null; if (getMediaStateListener() != null) title = getMediaStateListener().getTitle(); - playUri(mLocalVideoUri, title, mStartPositionMillis); + playUri(title, mStartPositionMillis); } private void showMessageToast(String message) { @@ -1060,7 +896,12 @@ private void configureNewSession(Bundle data) { mCurrentSessionId = data.getString(MediaControlIntent.EXTRA_SESSION_ID); mSessionState = MediaSessionStatus.SESSION_STATE_INVALIDATED; - RemotePlaybackSettings.setSessionId(getContext(), mCurrentSessionId); if (mDebug) Log.d(TAG, "Got a session id: " + mCurrentSessionId); } + + @Override + public String getUriPlaying() { + if (mLocalVideoUri == null) return null; + return mLocalVideoUri.toString(); + } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java index 6374b84..05b4f603 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/MediaRouteController.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.media.remote; import android.graphics.Bitmap; -import android.net.Uri; import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouter; import android.support.v7.media.MediaRouter.RouteInfo; @@ -203,23 +202,6 @@ boolean currentRouteSupportsRemotePlayback(); /** - * Checks if we want to reconnect, and if so starts trying to do so. Otherwise clears out the - * persistent request to reconnect. - */ - boolean reconnectAnyExistingRoute(); - - /** - * Sets the video URL when it becomes known. - * - * This is the original video URL but if there's URL redirection, it will change as resolved by - * {@link MediaUrlResolver}. - * - * @param uri The video URL. - * @param userAgent The browser user agent. - */ - void setDataSource(Uri uri, String cookies, String userAgent); - - /** * Setup this object to discover new routes and register the necessary players. */ void prepareMediaRoute(); @@ -249,14 +231,6 @@ boolean routeIsDefaultRoute(); /** - * Called to prepare the remote playback asyncronously. onPrepared() of the current remote media - * player object is called when the player is ready. - * - * @param startPositionMillis indicates where in the stream to start playing - */ - void prepareAsync(String frameUrl, long startPositionMillis); - - /** * Sets the remote volume of the current route. * * @param delta The delta value in arbitrary "Android Volume Units". @@ -348,11 +322,14 @@ /** * Called when a new route has been selected - * @param player TODO + * @param player The player {@link MediaStateListener} that initiated the connection * @param router The MediaRouter. * @param route The selected route. */ void onRouteSelected(MediaStateListener player, MediaRouter router, RouteInfo route); - + /** + * @return The Uri of the currently playing video + */ + @VisibleForTesting String getUriPlaying(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java index 7c38034c..d52b561e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/NotificationTransportControl.java
@@ -517,18 +517,12 @@ /** * Sets the MediaRouteController the notification should be using to get the data from. * - * @param mrc the MediaRouteController object to use. If null, the previous MediaRouteController - * object will not be overwritten. + * @param mrc the MediaRouteController object to use. */ private void setMediaRouteController(@Nullable MediaRouteController mrc) { - if (mrc == null || mMediaRouteController == mrc) return; - - if (mMediaRouteController != null) { - mMediaRouteController.removeUiListener(this); - } - + if (mMediaRouteController != null) mMediaRouteController.removeUiListener(this); mMediaRouteController = mrc; - mMediaRouteController.addUiListener(this); + if (mrc != null) mrc.addUiListener(this); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java index 83e29782..0fb7750 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemoteMediaPlayerController.java
@@ -55,8 +55,6 @@ // points to mDefaultRouteSelector, mYouTubeRouteSelector or null private MediaRouteController mCurrentRouteController; - private boolean mFirstConnection = true; - // This is a key for meta-data in the package manifest. private static final String REMOTE_MEDIA_PLAYERS_KEY = "org.chromium.content.browser.REMOTE_MEDIA_PLAYERS"; @@ -162,11 +160,6 @@ if (!controller.initialize()) return; - if (mFirstConnection) { - controller.reconnectAnyExistingRoute(); - mFirstConnection = false; - } - if (mNotificationControl != null) { mNotificationControl.setRouteController(controller); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemotePlaybackSettings.java b/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemotePlaybackSettings.java deleted file mode 100644 index aeb90be..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/remote/RemotePlaybackSettings.java +++ /dev/null
@@ -1,109 +0,0 @@ -// Copyright 2013 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.media.remote; - -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; - -/** - * Maintains the persistent settings that the app needs for casting. - */ -public class RemotePlaybackSettings { - private static final String DEVICE_ID_KEY = "remote_device_id"; - private static final String RECONNECT_KEY = "reconnect_remote_device"; - private static final String LAST_VIDEO_TIME_REMAINING_KEY = "last_video_time_remaining"; - private static final String LAST_VIDEO_TIME_PLAYED_KEY = "last_video_time_played"; - private static final String LAST_VIDEO_STATE_KEY = "last_video_state"; - private static final String PLAYER_IN_USE_KEY = "player_in_use"; - private static final String URI_PLAYING = "uri playing"; - private static final String SESSION_ID = "session_id"; - - public static String getDeviceId(Context context) { - return getPreferences(context).getString(DEVICE_ID_KEY, null); - } - - public static void setDeviceId(Context context, String deviceId) { - putValue(getPreferences(context), DEVICE_ID_KEY, deviceId); - } - - public static String getSessionId(Context context) { - return getPreferences(context).getString(SESSION_ID, null); - } - - public static void setSessionId(Context context, String sessionId) { - putValue(getPreferences(context), SESSION_ID, sessionId); - } - - public static boolean getShouldReconnectToRemote(Context context) { - return getPreferences(context).getBoolean(RECONNECT_KEY, false); - } - - public static void setShouldReconnectToRemote(Context context, boolean reconnect) { - putValue(getPreferences(context), RECONNECT_KEY, reconnect); - } - - public static long getRemainingTime(Context context) { - return getPreferences(context).getLong(LAST_VIDEO_TIME_REMAINING_KEY, 0); - } - - public static void setRemainingTime(Context context, long time) { - putValue(getPreferences(context), LAST_VIDEO_TIME_REMAINING_KEY, time); - } - - public static long getLastPlayedTime(Context context) { - return getPreferences(context).getLong(LAST_VIDEO_TIME_PLAYED_KEY, 0); - } - - public static void setLastPlayedTime(Context context, long time) { - putValue(getPreferences(context), LAST_VIDEO_TIME_PLAYED_KEY, time); - } - - public static String getLastVideoState(Context context) { - return getPreferences(context).getString(LAST_VIDEO_STATE_KEY, null); - } - - public static void setLastVideoState(Context context, String title) { - putValue(getPreferences(context), LAST_VIDEO_STATE_KEY, title); - } - - public static String getPlayerInUse(Context context) { - return getPreferences(context).getString(PLAYER_IN_USE_KEY, null); - } - - public static void setPlayerInUse(Context context, String player) { - putValue(getPreferences(context), PLAYER_IN_USE_KEY, player); - } - - public static String getUriPlaying(Context context) { - return getPreferences(context).getString(URI_PLAYING, null); - } - - public static void setUriPlaying(Context context, String url) { - putValue(getPreferences(context), URI_PLAYING, url); - } - - private static void putValue(SharedPreferences preferences, String key, String value) { - SharedPreferences.Editor editor = preferences.edit(); - editor.putString(key, value); - editor.apply(); - } - - private static void putValue(SharedPreferences preferences, String key, boolean value) { - SharedPreferences.Editor editor = preferences.edit(); - editor.putBoolean(key, value); - editor.apply(); - } - - private static void putValue(SharedPreferences preferences, String key, long value) { - SharedPreferences.Editor editor = preferences.edit(); - editor.putLong(key, value); - editor.apply(); - } - - private static SharedPreferences getPreferences(Context context) { - return PreferenceManager.getDefaultSharedPreferences(context); - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java index 3797ab0..84d168a9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/signin/SigninHelper.java
@@ -210,7 +210,7 @@ } if (mProfileSyncService != null && AndroidSyncSettings.isSyncEnabled(mContext)) { - if (mProfileSyncService.hasSyncSetupCompleted()) { + if (mProfileSyncService.isFirstSetupComplete()) { if (accountsChanged) { // Nudge the syncer to ensure it does a full sync. InvalidationServiceFactory.getForProfile(Profile.getLastUsedProfile())
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java index 8483539..62b7f77 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ProfileSyncService.java
@@ -351,12 +351,18 @@ ? ALL_SELECTABLE_TYPES : modelTypeSetToArray(enabledTypes)); } - public void setSyncSetupCompleted() { - nativeSetSyncSetupCompleted(mNativeProfileSyncServiceAndroid); + public void setFirstSetupComplete() { + nativeSetFirstSetupComplete(mNativeProfileSyncServiceAndroid); } - public boolean hasSyncSetupCompleted() { - return nativeHasSyncSetupCompleted(mNativeProfileSyncServiceAndroid); + // TODO(maxbogue): Remove when downstream is updated to use the above. + @Deprecated + public void setSyncSetupCompleted() { + nativeSetFirstSetupComplete(mNativeProfileSyncServiceAndroid); + } + + public boolean isFirstSetupComplete() { + return nativeIsFirstSetupComplete(mNativeProfileSyncServiceAndroid); } public boolean isSyncRequested() { @@ -560,8 +566,8 @@ long nativeProfileSyncServiceAndroid, boolean syncEverything, int[] modelTypeArray); private native void nativeSetSetupInProgress( long nativeProfileSyncServiceAndroid, boolean inProgress); - private native void nativeSetSyncSetupCompleted(long nativeProfileSyncServiceAndroid); - private native boolean nativeHasSyncSetupCompleted(long nativeProfileSyncServiceAndroid); + private native void nativeSetFirstSetupComplete(long nativeProfileSyncServiceAndroid); + private native boolean nativeIsFirstSetupComplete(long nativeProfileSyncServiceAndroid); private native boolean nativeIsSyncRequested(long nativeProfileSyncServiceAndroid); private native boolean nativeIsSyncActive(long nativeProfileSyncServiceAndroid); private native boolean nativeHasKeepEverythingSynced(long nativeProfileSyncServiceAndroid);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java index 2b6e3fd8..e1b728f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/ui/SyncCustomizationFragment.java
@@ -245,7 +245,7 @@ // Save the new data type state. configureSyncDataTypes(); // Inform sync that the user has finished setting up sync at least once. - mProfileSyncService.setSyncSetupCompleted(); + mProfileSyncService.setFirstSetupComplete(); } // Setup is done. This was preventing sync from turning on even if it was enabled. mProfileSyncService.setSetupInProgress(false);
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd index 8b9b17c3..cbaaf07f 100644 --- a/chrome/android/java/strings/android_chrome_strings.grd +++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1453,6 +1453,9 @@ <message name="IDS_DOWNLOAD_NOTIFICATION_PAUSED" desc="Download notification to be displayed when a download pauses."> Download paused. </message> + <message name="IDS_DOWNLOAD_NOTIFICATION_RESUME_BUTTON" desc="Text on the button that resumes a paused download."> + Resume + </message> <message name="IDS_DOWNLOAD_FAILED_REASON_FILE_ALREADY_EXISTS" desc="Message to explain that the download failed because file already exists."> <ph name="FILE_NAME">%1$s<ex>http://abc.com/test.pdf</ex></ph> download prevented because file already exists. </message>
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java index b64361c..916bd59 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabExternalNavigationTest.java
@@ -6,7 +6,6 @@ import android.app.Activity; import android.os.Bundle; -import android.test.FlakyTest; import android.test.suitebuilder.annotation.SmallTest; import org.chromium.chrome.browser.customtabs.CustomTabDelegateFactory.CustomTabNavigationDelegate; @@ -81,11 +80,8 @@ /** * When loading a normal http url that chrome is able to handle, an intent picker should never * be shown, even if other activities such as {@link DummyActivityForHttp} claim to handle it. - * - * crbug.com/519613 - * @SmallTest */ - @FlakyTest + @SmallTest public void testIntentPickerNotShownForNormalUrl() { final String testUrl = "http://customtabtest.com"; ExternalNavigationParams params = new ExternalNavigationParams.Builder(testUrl, false)
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 d482a981..efa4f28 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
@@ -255,6 +255,9 @@ protected long addCompletedDownload(DownloadInfo downloadInfo) { return 1L; } + + @Override + protected void init() {} } private static Handler getTestHandler() { @@ -419,15 +422,11 @@ assertTrue("All downloads should be updated.", matchSet.mMatches.isEmpty()); // Check if notifications are removed when clearPendingNotifications is called. - matchSet = new OneTimeMatchSet(download1.getDownloadId(), - download2.getDownloadId(), download3.getDownloadId()); - notifier.expect(MethodID.CANCEL_DOWNLOAD_ID, matchSet) - .andThen(MethodID.CANCEL_DOWNLOAD_ID, matchSet) - .andThen(MethodID.CANCEL_DOWNLOAD_ID, matchSet); - dService.clearPendingDownloadNotifications(); - notifier.waitTillExpectedCallsComplete(); - assertTrue("All downloads should be removed.", matchSet.mMatches.isEmpty()); + Set<String> downloads = dService.getStoredDownloadInfo( + PreferenceManager.getDefaultSharedPreferences(getTestContext()), + DownloadManagerService.PENDING_DOWNLOAD_NOTIFICATIONS); + assertTrue("All downloads should be removed.", downloads.isEmpty()); } /** @@ -567,4 +566,21 @@ .build())); } + @SmallTest + @Feature({"Download"}) + public void testParseDownloadNotifications() { + String notification = "1,0,test.pdf"; + DownloadManagerService.PendingNotification pendingNotification = + DownloadManagerService.PendingNotification.parseFromString(notification); + assertEquals(1, pendingNotification.downloadId); + assertEquals("test.pdf", pendingNotification.fileName); + assertFalse(pendingNotification.isResumable); + + notification = "2,1,test,2.pdf"; + pendingNotification = + DownloadManagerService.PendingNotification.parseFromString(notification); + assertEquals(2, pendingNotification.downloadId); + assertEquals("test,2.pdf", pendingNotification.fileName); + assertTrue(pendingNotification.isResumable); + } }
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 a92991c..51507d7 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
@@ -73,8 +73,10 @@ Context mockContext = new AdvancedMockContext(getSystemContext()); getService().setContext(mockContext); Set<String> notifications = new HashSet<String>(); - notifications.add(DownloadManagerService.getNotificationString(1, "test1")); - notifications.add(DownloadManagerService.getNotificationString(2, "test2")); + notifications.add(new DownloadManagerService.PendingNotification( + 1, "test1", true).getNotificationString()); + notifications.add(new DownloadManagerService.PendingNotification( + 2, "test2", true).getNotificationString()); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(mockContext); SharedPreferences.Editor editor = sharedPrefs.edit();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java index 1778a51..7b04135 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastSwitchVideoTest.java
@@ -131,9 +131,8 @@ startSecondVideo.run(); // Check that we are still casting the default video - assertEquals("The first video is not casting", - TestHttpServerClient.getUrl(DEFAULT_VIDEO), - RemotePlaybackSettings.getUriPlaying(getActivity())); + assertEquals("The first video is not casting", TestHttpServerClient.getUrl(DEFAULT_VIDEO), + getUriPlaying()); // Check that the second video is still there and paused final Tab tab = getActivity().getActivityTab();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java index 861e31b..f0b6bbf 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastTestBase.java
@@ -111,6 +111,8 @@ private boolean mPlaying = false; + private MediaRouteController mMediaRouteController; + private StrictMode.ThreadPolicy mOldPolicy; public CastTestBase() { @@ -204,8 +206,6 @@ protected Rect prepareDefaultVideofromPage(String pagePath, Tab currentTab) throws InterruptedException, TimeoutException { - // Ensure that we don't try to reconnect - RemotePlaybackSettings.setShouldReconnectToRemote(getActivity(), false); loadUrl(TestHttpServerClient.getUrl(pagePath)); @@ -242,14 +242,11 @@ public void run() { RemoteMediaPlayerController playerController = RemoteMediaPlayerController.instance(); - - // Because of the way we fake YouTube this will get the YouTube controller if we are - // testing YouTube. - MediaRouteController routeController = playerController.getMediaRouteController( + mMediaRouteController = playerController.getMediaRouteController( TestHttpServerClient.getUrl(DEFAULT_VIDEO), TestHttpServerClient.getUrl(DEFAULT_VIDEO_PAGE)); - assertNotNull("Could not get MediaRouteController", routeController); - routeController.addUiListener(new TestListener()); + assertNotNull("Could not get MediaRouteController", mMediaRouteController); + mMediaRouteController.addUiListener(new TestListener()); } }); tapCastButton(tab, videoRect); @@ -303,8 +300,7 @@ if (notificationTransportControl != null && notificationTransportControl.isShowing()) { fail("Failed to close notification"); } - assertEquals("Video still playing?", null, - RemotePlaybackSettings.getUriPlaying(getActivity())); + assertEquals("Video still playing?", null, getUriPlaying()); assertTrue("RemoteMediaPlayerController not stopped", !isPlayingRemotely()); } @@ -349,8 +345,8 @@ assertTrue("No notification", notificationTransportControl.isShowing()); // Check that we are playing the right video waitUntilVideoCurrent(testVideo); - assertEquals("Wrong video playing", TestHttpServerClient.getUrl(testVideo), - RemotePlaybackSettings.getUriPlaying(getActivity())); + assertEquals( + "Wrong video playing", TestHttpServerClient.getUrl(testVideo), getUriPlaying()); // Check that the RemoteMediaPlayerController and the (YouTube)MediaRouteController have // been set up correctly @@ -411,7 +407,7 @@ protected View waitForView(Callable<View> getViewCallable, int timeoutMs) { for (int time = 0; time < timeoutMs; time += VIEW_RETRY_MS) { try { - View result = getViewCallable.call(); + View result = ThreadUtils.runOnUiThreadBlocking(getViewCallable); if (result != null) return result; } catch (Exception e) { fail(e.toString()); @@ -423,7 +419,13 @@ protected NotificationTransportControl waitForCastNotification() { for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { - NotificationTransportControl result = NotificationTransportControl.getIfExists(); + NotificationTransportControl result = ThreadUtils.runOnUiThreadBlockingNoException( + new Callable<NotificationTransportControl>() { + @Override + public NotificationTransportControl call() { + return NotificationTransportControl.getIfExists(); + } + }); if (result != null) { return result; } @@ -433,28 +435,39 @@ } protected NotificationTransportControl.ListenerService waitForCastNotificationService( - NotificationTransportControl notification) { + final NotificationTransportControl notification) { for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { - NotificationTransportControl.ListenerService service = notification.getService(); + NotificationTransportControl.ListenerService service = + ThreadUtils.runOnUiThreadBlockingNoException( + new Callable<NotificationTransportControl.ListenerService>() { + @Override + public NotificationTransportControl.ListenerService call() { + return notification.getService(); + } + }); if (service != null) { return service; } sleepNoThrow(VIEW_RETRY_MS); } return null; - } - protected boolean waitForState(RemoteVideoInfo.PlayerState state) { + protected boolean waitForState(final RemoteVideoInfo.PlayerState state) { for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { - RemoteMediaPlayerController playerController = RemoteMediaPlayerController - .getIfExists(); - if (playerController != null - && playerController.getCurrentlyPlayingMediaRouteController() != null - && playerController.getCurrentlyPlayingMediaRouteController().getPlayerState() - == state) { - return true; - } + boolean result = ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { + @Override + public Boolean call() { + RemoteMediaPlayerController playerController = + RemoteMediaPlayerController.getIfExists(); + return playerController != null + && playerController.getCurrentlyPlayingMediaRouteController() != null + && playerController.getCurrentlyPlayingMediaRouteController() + .getPlayerState() + == state; + } + }); + if (result) return true; sleepNoThrow(VIEW_RETRY_MS); } return false; @@ -462,26 +475,37 @@ protected boolean waitUntilPlaying() { for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { - if (mPlaying) return true; + boolean playing = ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { + @Override + public Boolean call() { + return mPlaying; + } + }); + if (playing) return true; sleepNoThrow(VIEW_RETRY_MS); } return false; } private boolean isDisconnected() { - NotificationTransportControl notificationTransportControl = - NotificationTransportControl.getIfExists(); - if (notificationTransportControl != null && notificationTransportControl.isShowing()) { - return false; - } - if (RemotePlaybackSettings.getUriPlaying(getActivity()) != null) return false; - return !isPlayingRemotely(); + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { + @Override + public Boolean call() { + NotificationTransportControl notificationTransportControl = + NotificationTransportControl.getIfExists(); + if (notificationTransportControl != null + && notificationTransportControl.isShowing()) { + return false; + } + if (getUriPlaying() != null) return false; + return !isPlayingRemotely(); + } + }); } private boolean waitUntilVideoCurrent(String testVideo) { for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { - if (TestHttpServerClient.getUrl(testVideo).equals( - RemotePlaybackSettings.getUriPlaying(getActivity()))) { + if (TestHttpServerClient.getUrl(testVideo).equals(getUriPlaying())) { return true; } sleepNoThrow(VIEW_RETRY_MS); @@ -489,30 +513,62 @@ return false; } + protected String getUriPlaying() { + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<String>() { + @Override + public String call() { + if (mMediaRouteController == null) return ""; + return mMediaRouteController.getUriPlaying(); + } + }); + } + protected long getRemotePositionMs() { - return getMediaRouteController().getPosition(); + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Long>() { + @Override + public Long call() { + return getMediaRouteController().getPosition(); + } + }); } protected long getRemoteDurationMs() { - return getMediaRouteController().getDuration(); + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Long>() { + @Override + public Long call() { + return getMediaRouteController().getDuration(); + } + }); } protected boolean isPlayingRemotely() { - RemoteMediaPlayerController playerController = RemoteMediaPlayerController.getIfExists(); - if (playerController == null) return false; - MediaRouteController routeController = playerController - .getCurrentlyPlayingMediaRouteController(); - if (routeController == null) return false; - return routeController.isPlaying(); + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { + @Override + public Boolean call() { + RemoteMediaPlayerController playerController = + RemoteMediaPlayerController.getIfExists(); + if (playerController == null) return false; + MediaRouteController routeController = + playerController.getCurrentlyPlayingMediaRouteController(); + if (routeController == null) return false; + return routeController.isPlaying(); + } + }); } protected MediaRouteController getMediaRouteController() { - RemoteMediaPlayerController playerController = RemoteMediaPlayerController.getIfExists(); - assertNotNull("No RemoteMediaPlayerController", playerController); - MediaRouteController routeController = playerController - .getCurrentlyPlayingMediaRouteController(); - assertNotNull("No MediaRouteController", routeController); - return routeController; + return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<MediaRouteController>() { + @Override + public MediaRouteController call() { + RemoteMediaPlayerController playerController = + RemoteMediaPlayerController.getIfExists(); + assertNotNull("No RemoteMediaPlayerController", playerController); + MediaRouteController routeController = + playerController.getCurrentlyPlayingMediaRouteController(); + assertNotNull("No MediaRouteController", routeController); + return routeController; + } + }); } /*
diff --git a/chrome/android/junit/DEPS b/chrome/android/junit/DEPS index d3208c73..bca590f 100644 --- a/chrome/android/junit/DEPS +++ b/chrome/android/junit/DEPS
@@ -1,4 +1,6 @@ include_rules = [ + "+components/bookmarks/common/android", + "+content/public/android/java", "+sync/android/java/src/org/chromium/sync", "+sync/test/android/javatests/src/org/chromium/sync/test/util", ]
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtilsTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtilsTest.java new file mode 100644 index 0000000..f6133d0 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtilsTest.java
@@ -0,0 +1,69 @@ +// 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. + +package org.chromium.chrome.browser.enhancedbookmarks; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; + +import org.chromium.base.test.util.Feature; +import org.chromium.components.bookmarks.BookmarkId; +import org.chromium.components.bookmarks.BookmarkType; +import org.chromium.content_public.browser.WebContents; +import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.annotation.Config; + +/** + * Robolectric tests for {@link EnhancedBookmarkUtils}. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class EnhancedBookmarkUtilsTest { + @Mock private Context mContext; + @Mock private EnhancedBookmarksModel mEnhancedBookmarksModel; + @Mock private WebContents mWebContents; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + } + + @Test + @Feature({"Bookmark"}) + public void testStartEditActivityWithoutWebContents() { + BookmarkId bookmarkId = new BookmarkId(12345L, BookmarkType.NORMAL); + EnhancedBookmarkUtils.startEditActivity(mContext, bookmarkId, null /* webContents */); + ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + + verify(mContext).startActivity(intentArgumentCaptor.capture()); + + // Verify that the intent doesn't contain the WEB_CONTENTS extra. + assertFalse(intentArgumentCaptor.getValue() + .hasExtra(EnhancedBookmarkEditActivity.INTENT_WEB_CONTENTS)); + } + + @Test + @Feature({"Bookmark"}) + public void testStartEditActivityWithWebContents() { + BookmarkId bookmarkId = new BookmarkId(12345L, BookmarkType.NORMAL); + EnhancedBookmarkUtils.startEditActivity(mContext, bookmarkId, mWebContents); + ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class); + + verify(mContext).startActivity(intentArgumentCaptor.capture()); + + // Verify that the intent contains the right WEB_CONTENTS extra. + assertEquals(mWebContents, intentArgumentCaptor.getValue() + .getParcelableExtra(EnhancedBookmarkEditActivity.INTENT_WEB_CONTENTS)); + } +}
diff --git a/chrome/app/DEPS b/chrome/app/DEPS index 5d647ee..05ddeef3 100644 --- a/chrome/app/DEPS +++ b/chrome/app/DEPS
@@ -21,6 +21,7 @@ "+components/nacl/zygote", "+components/policy/core/browser/android", "+components/startup_metric_utils/browser", + "+components/startup_metric_utils/common", "+components/upload_list", "+components/version_info", "+content/public/app",
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc index 203741db..a70a678 100644 --- a/chrome/app/main_dll_loader_win.cc +++ b/chrome/app/main_dll_loader_win.cc
@@ -47,7 +47,7 @@ #include "chrome/installer/util/util_constants.h" #include "components/crash/content/app/crash_reporter_client.h" #include "components/crash/content/app/crashpad.h" -#include "components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "content/public/app/sandbox_helper_win.h" #include "content/public/common/content_switches.h" #include "sandbox/win/src/sandbox.h"
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 87bcd4c2..5a5c8120 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -853,6 +853,7 @@ "//chrome_elf:dll_hash", "//components/browser_watcher", "//components/browser_watcher:browser_watcher_client", + "//components/startup_metric_utils/common", "//google_update", "//third_party/iaccessible2", "//third_party/isimpledom", @@ -1310,6 +1311,8 @@ sources = [ "password_manager/password_manager_test_base.cc", "password_manager/password_manager_test_base.h", + "signin/token_revoker_test_utils.cc", + "signin/token_revoker_test_utils.h", "ui/webui/signin/login_ui_test_utils.cc", "ui/webui/signin/login_ui_test_utils.h", ]
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS index ad690f8..84d5266f 100644 --- a/chrome/browser/DEPS +++ b/chrome/browser/DEPS
@@ -102,6 +102,7 @@ "+components/ssl_config", "+components/ssl_errors", "+components/startup_metric_utils/browser", + "+components/startup_metric_utils/common", "+components/storage_monitor", "+components/strings", "+components/suggestions",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index a2b41f50..470ec6f 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -755,7 +755,7 @@ {"enable-web-bluetooth", IDS_FLAGS_WEB_BLUETOOTH_NAME, IDS_FLAGS_WEB_BLUETOOTH_DESCRIPTION, - kOsCrOS | kOsMac | kOsAndroid, + kOsCrOS | kOsMac | kOsAndroid | kOsLinux, SINGLE_VALUE_TYPE(switches::kEnableWebBluetooth)}, #if defined(ENABLE_EXTENSIONS) {"enable-ble-advertising-in-apps",
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index a0f30cc..ec04fc9b 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -39,6 +39,7 @@ #include "chrome/browser/android/document/document_web_contents_delegate.h" #include "chrome/browser/android/dom_distiller/distiller_ui_handle_android.h" #include "chrome/browser/android/download/chrome_download_delegate.h" +#include "chrome/browser/android/download/download_manager_service.h" #include "chrome/browser/android/favicon_helper.h" #include "chrome/browser/android/feature_utilities.h" #include "chrome/browser/android/feedback/connectivity_checker.h" @@ -255,6 +256,8 @@ {"DomDistillerServiceFactory", dom_distiller::android::DomDistillerServiceFactoryAndroid::Register}, {"DomDistillerTabUtils", RegisterDomDistillerTabUtils}, + {"DownloadManagerService", + DownloadManagerService::RegisterDownloadManagerService}, {"DownloadOverwriteInfoBarDelegate", RegisterDownloadOverwriteInfoBarDelegate}, {"EditBookmarkHelper", RegisterEditBookmarkHelper},
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc new file mode 100644 index 0000000..3d4fe8a --- /dev/null +++ b/chrome/browser/android/download/download_manager_service.cc
@@ -0,0 +1,121 @@ +// 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 "chrome/browser/android/download/download_manager_service.h" + +#include "base/android/jni_string.h" +#include "base/message_loop/message_loop.h" +#include "base/time/time.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "content/public/browser/android/download_controller_android.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/download_item.h" +#include "jni/DownloadManagerService_jni.h" + +using base::android::JavaParamRef; +using base::android::ConvertJavaStringToUTF8; +using base::android::ConvertUTF8ToJavaString; + +namespace { +// The retry interval when resuming a download. This is needed because +// when the browser process is launched, we have to wait until the download +// history get loaded before a download can be resumed. However, we don't want +// to retry after a long period of time as the same download Id can be reused +// later. +const int kResumeRetryIntervalInMilliseconds = 3000; +} + +// static +bool DownloadManagerService::RegisterDownloadManagerService(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) { + Profile* profile = ProfileManager::GetActiveUserProfile(); + content::DownloadManager* manager = + content::BrowserContext::GetDownloadManager(profile); + DownloadManagerService* service = + new DownloadManagerService(env, jobj, manager); + return reinterpret_cast<intptr_t>(service); +} + +DownloadManagerService::DownloadManagerService( + JNIEnv* env, + jobject obj, + content::DownloadManager* manager) + : java_ref_(env, obj), manager_(manager) { + manager_->AddObserver(this); +} + +DownloadManagerService::~DownloadManagerService() { + if (manager_) + manager_->RemoveObserver(this); +} + +void DownloadManagerService::ResumeDownload(JNIEnv* env, + jobject obj, + uint32_t download_id, + jstring fileName) { + ResumeDownloadInternal(download_id, ConvertJavaStringToUTF8(env, fileName), + true); +} + +void DownloadManagerService::ManagerGoingDown( + content::DownloadManager* manager) { + manager_ = nullptr; +} + +void DownloadManagerService::ResumeDownloadItem(content::DownloadItem* item, + const std::string& fileName) { + if (!item->CanResume()) { + OnResumptionFailed(item->GetId(), fileName); + return; + } + item->AddObserver(content::DownloadControllerAndroid::Get()); + item->Resume(); + if (!resume_callback_for_testing_.is_null()) + resume_callback_for_testing_.Run(true); +} + +void DownloadManagerService::ResumeDownloadInternal(uint32_t download_id, + const std::string& fileName, + bool retry) { + if (!manager_) { + OnResumptionFailed(download_id, fileName); + return; + } + content::DownloadItem* item = manager_->GetDownload(download_id); + if (item) { + ResumeDownloadItem(item, fileName); + return; + } + if (!retry) { + OnResumptionFailed(download_id, fileName); + return; + } + // Post a delayed task to wait for the download history to load the download + // item. If the download item is not loaded when the delayed task runs, show + // an download failed notification. Alternatively, we can have the + // DownloadManager inform us when a download item is created. However, there + // is no guarantee when the download item will be created, since the newly + // created item might not be loaded from download history. So user might wait + // indefinitely to see the failed notification. See http://crbug.com/577893. + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&DownloadManagerService::ResumeDownloadInternal, + base::Unretained(this), download_id, fileName, false), + base::TimeDelta::FromMilliseconds(kResumeRetryIntervalInMilliseconds)); +} + +void DownloadManagerService::OnResumptionFailed(uint32_t download_id, + const std::string& fileName) { + if (!java_ref_.is_null()) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_DownloadManagerService_onResumptionFailed( + env, java_ref_.obj(), download_id, + ConvertUTF8ToJavaString(env, fileName).obj()); + } + if (!resume_callback_for_testing_.is_null()) + resume_callback_for_testing_.Run(false); +}
diff --git a/chrome/browser/android/download/download_manager_service.h b/chrome/browser/android/download/download_manager_service.h new file mode 100644 index 0000000..6d5a935a --- /dev/null +++ b/chrome/browser/android/download/download_manager_service.h
@@ -0,0 +1,76 @@ +// 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. + +#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_ +#define CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_ + +#include <jni.h> +#include <string> + +#include "base/android/scoped_java_ref.h" +#include "base/callback.h" +#include "base/macros.h" +#include "content/public/browser/download_manager.h" + +namespace content { +class DownloadItem; +} + +// Native side of DownloadManagerService.java. The native object is owned by its +// Java object. +class DownloadManagerService : public content::DownloadManager::Observer { + public: + // JNI registration. + static bool RegisterDownloadManagerService(JNIEnv* env); + + DownloadManagerService(JNIEnv* env, + jobject jobj, + content::DownloadManager* manager); + ~DownloadManagerService() override; + + // Called to resume downloading the item that has ID equal to |download_id|. + // If the DownloadItem is not yet created, put the ID into + // |pending_download_ids_|. + void ResumeDownload(JNIEnv* env, + jobject obj, + uint32_t download_id, + jstring fileName); + + // content::DownloadManager::Observer methods. + void ManagerGoingDown(content::DownloadManager* manager) override; + + private: + // For testing. + friend class DownloadManagerServiceTest; + + // Resume downloading the given DownloadItem. + void ResumeDownloadItem(content::DownloadItem* item, + const std::string& fileName); + + // Helper function to start the download resumption. If |retry| is true, + // chrome will retry the resumption if the download item is not loaded. + void ResumeDownloadInternal(uint32_t download_id, + const std::string& fileName, + bool retry); + + // Called to notify the java side that download resumption failed. + void OnResumptionFailed(uint32_t download_id, const std::string& fileName); + + typedef base::Callback<void(bool)> ResumeCallback; + void set_resume_callback_for_testing(const ResumeCallback& resume_cb) { + resume_callback_for_testing_ = resume_cb; + } + + // Reference to the Java object. + base::android::ScopedJavaGlobalRef<jobject> java_ref_; + + // Download manager this class observes + content::DownloadManager* manager_; + + ResumeCallback resume_callback_for_testing_; + + DISALLOW_COPY_AND_ASSIGN(DownloadManagerService); +}; + +#endif // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MANAGER_SERVICE_H_
diff --git a/chrome/browser/android/download/download_manager_service_unittest.cc b/chrome/browser/android/download/download_manager_service_unittest.cc new file mode 100644 index 0000000..c400c8a --- /dev/null +++ b/chrome/browser/android/download/download_manager_service_unittest.cc
@@ -0,0 +1,222 @@ +// 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 "chrome/browser/android/download/download_manager_service.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/bind.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "content/public/browser/download_item.h" +#include "content/public/browser/download_manager.h" +#include "content/public/browser/download_url_parameters.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/origin.h" + +using ::testing::_; + +namespace content { +class BrowserContext; +class ByteStreamReader; +class DownloadManagerDelegate; +struct DownloadCreateInfo; +} + +// Mock implementation of content::DownloadItem. +class MockDownloadItem : public content::DownloadItem { + public: + explicit MockDownloadItem(bool can_resume) : can_resume_(can_resume) {} + ~MockDownloadItem() override {} + bool CanResume() const override { return can_resume_; } + + MOCK_METHOD1(AddObserver, void(content::DownloadItem::Observer*)); + MOCK_METHOD1(RemoveObserver, void(content::DownloadItem::Observer*)); + MOCK_METHOD0(UpdateObservers, void()); + MOCK_METHOD0(ValidateDangerousDownload, void()); + MOCK_METHOD1(StealDangerousDownload, + void(const content::DownloadItem::AcquireFileCallback&)); + MOCK_METHOD0(Pause, void()); + MOCK_METHOD0(Resume, void()); + MOCK_METHOD1(Cancel, void(bool)); + MOCK_METHOD0(Remove, void()); + MOCK_METHOD0(OpenDownload, void()); + MOCK_METHOD0(ShowDownloadInShell, void()); + MOCK_CONST_METHOD0(GetId, uint32_t()); + MOCK_CONST_METHOD0(GetState, content::DownloadItem::DownloadState()); + MOCK_CONST_METHOD0(GetLastReason, content::DownloadInterruptReason()); + MOCK_CONST_METHOD0(IsPaused, bool()); + MOCK_CONST_METHOD0(IsTemporary, bool()); + MOCK_CONST_METHOD0(IsDone, bool()); + MOCK_CONST_METHOD0(GetURL, const GURL&()); + MOCK_CONST_METHOD0(GetUrlChain, std::vector<GURL>&()); + MOCK_CONST_METHOD0(GetOriginalUrl, const GURL&()); + MOCK_CONST_METHOD0(GetReferrerUrl, const GURL&()); + MOCK_CONST_METHOD0(GetTabUrl, const GURL&()); + MOCK_CONST_METHOD0(GetTabReferrerUrl, const GURL&()); + MOCK_CONST_METHOD0(GetSuggestedFilename, std::string()); + MOCK_CONST_METHOD0(GetContentDisposition, std::string()); + MOCK_CONST_METHOD0(GetMimeType, std::string()); + MOCK_CONST_METHOD0(GetOriginalMimeType, std::string()); + MOCK_CONST_METHOD0(GetRemoteAddress, std::string()); + MOCK_CONST_METHOD0(HasUserGesture, bool()); + MOCK_CONST_METHOD0(GetTransitionType, ui::PageTransition()); + MOCK_CONST_METHOD0(GetLastModifiedTime, const std::string&()); + MOCK_CONST_METHOD0(GetETag, const std::string&()); + MOCK_CONST_METHOD0(IsSavePackageDownload, bool()); + MOCK_CONST_METHOD0(GetFullPath, const base::FilePath&()); + MOCK_CONST_METHOD0(GetTargetFilePath, const base::FilePath&()); + MOCK_CONST_METHOD0(GetForcedFilePath, const base::FilePath&()); + MOCK_CONST_METHOD0(GetFileNameToReportUser, base::FilePath()); + MOCK_CONST_METHOD0(GetTargetDisposition, + content::DownloadItem::TargetDisposition()); + MOCK_CONST_METHOD0(GetHash, const std::string&()); + MOCK_CONST_METHOD0(GetHashState, const std::string&()); + MOCK_CONST_METHOD0(GetFileExternallyRemoved, bool()); + MOCK_METHOD1(DeleteFile, void(const base::Callback<void(bool)>&)); + MOCK_CONST_METHOD0(IsDangerous, bool()); + MOCK_CONST_METHOD0(GetDangerType, content::DownloadDangerType()); + MOCK_CONST_METHOD1(TimeRemaining, bool(base::TimeDelta*)); + MOCK_CONST_METHOD0(CurrentSpeed, int64_t()); + MOCK_CONST_METHOD0(PercentComplete, int()); + MOCK_CONST_METHOD0(AllDataSaved, bool()); + MOCK_CONST_METHOD0(GetTotalBytes, int64_t()); + MOCK_CONST_METHOD0(GetReceivedBytes, int64_t()); + MOCK_CONST_METHOD0(GetStartTime, base::Time()); + MOCK_CONST_METHOD0(GetEndTime, base::Time()); + MOCK_METHOD0(CanShowInFolder, bool()); + MOCK_METHOD0(CanOpenDownload, bool()); + MOCK_METHOD0(ShouldOpenFileBasedOnExtension, bool()); + MOCK_CONST_METHOD0(GetOpenWhenComplete, bool()); + MOCK_METHOD0(GetAutoOpened, bool()); + MOCK_CONST_METHOD0(GetOpened, bool()); + MOCK_CONST_METHOD0(GetBrowserContext, content::BrowserContext*()); + MOCK_CONST_METHOD0(GetWebContents, content::WebContents*()); + MOCK_METHOD1(OnContentCheckCompleted, void(content::DownloadDangerType)); + MOCK_METHOD1(SetOpenWhenComplete, void(bool)); + MOCK_METHOD1(SetIsTemporary, void(bool)); + MOCK_METHOD1(SetOpened, void(bool)); + MOCK_METHOD1(SetDisplayName, void(const base::FilePath&)); + MOCK_CONST_METHOD1(DebugString, std::string(bool)); + + private: + bool can_resume_; +}; + +// Mock implementation of content::DownloadManager. +class MockDownloadManager : public content::DownloadManager { + public: + MockDownloadManager() {} + ~MockDownloadManager() override {} + + MOCK_METHOD1(SetDelegate, void(content::DownloadManagerDelegate*)); + MOCK_CONST_METHOD0(GetDelegate, content::DownloadManagerDelegate*()); + MOCK_METHOD0(Shutdown, void()); + MOCK_METHOD1(GetAllDownloads, void(DownloadVector*)); + MOCK_METHOD3(RemoveDownloadsByOriginAndTime, + int(const url::Origin&, base::Time, base::Time)); + MOCK_METHOD2(RemoveDownloadsBetween, int(base::Time, base::Time)); + MOCK_METHOD1(RemoveDownloads, int(base::Time)); + MOCK_METHOD0(RemoveAllDownloads, int()); + void DownloadUrl(scoped_ptr<content::DownloadUrlParameters>) override {} + MOCK_METHOD1(AddObserver, void(content::DownloadManager::Observer*)); + MOCK_METHOD1(RemoveObserver, void(content::DownloadManager::Observer*)); + MOCK_CONST_METHOD0(InProgressCount, int()); + MOCK_CONST_METHOD0(NonMaliciousInProgressCount, int()); + MOCK_CONST_METHOD0(GetBrowserContext, content::BrowserContext*()); + MOCK_METHOD0(CheckForHistoryFilesRemoval, void()); + void StartDownload( + scoped_ptr<content::DownloadCreateInfo>, + scoped_ptr<content::ByteStreamReader>, + const content::DownloadUrlParameters::OnStartedCallback&) override {} + content::DownloadItem* CreateDownloadItem( + uint32_t id, + const base::FilePath& current_path, + const base::FilePath& target_path, + const std::vector<GURL>& url_chain, + const GURL& referrer_url, + const std::string& mime_type, + const std::string& original_mime_type, + const base::Time& start_time, + const base::Time& end_time, + const std::string& etag, + const std::string& last_modified, + int64_t received_bytes, + int64_t total_bytes, + content::DownloadItem::DownloadState state, + content::DownloadDangerType danger_type, + content::DownloadInterruptReason interrupt_reason, + bool opened) override { + return nullptr; + } + content::DownloadItem* GetDownload(uint32_t id) override { + return download_item_.get(); + } + void SetDownload(MockDownloadItem* item) { download_item_.reset(item); } + + private: + scoped_ptr<MockDownloadItem> download_item_; +}; + +class DownloadManagerServiceTest : public testing::Test { + public: + DownloadManagerServiceTest() + : service_( + new DownloadManagerService(base::android::AttachCurrentThread(), + nullptr, + &manager_)), + finished_(false), + success_(false) {} + + void OnResumptionDone(bool success) { + finished_ = true; + success_ = success; + } + + void StartDownload(int download_id) { + JNIEnv* env = base::android::AttachCurrentThread(); + service_->set_resume_callback_for_testing(base::Bind( + &DownloadManagerServiceTest::OnResumptionDone, base::Unretained(this))); + service_->ResumeDownload( + env, nullptr, download_id, + base::android::ConvertUTF8ToJavaString(env, "test").obj()); + while (!finished_) + message_loop_.RunUntilIdle(); + } + + void CreateDownloadItem(bool can_resume) { + manager_.SetDownload(new MockDownloadItem(can_resume)); + } + + protected: + base::MessageLoop message_loop_; + MockDownloadManager manager_; + DownloadManagerService* service_; + bool finished_; + bool success_; + + DISALLOW_COPY_AND_ASSIGN(DownloadManagerServiceTest); +}; + +// Test that resumption will fail if no download item is found before times out. +TEST_F(DownloadManagerServiceTest, ResumptionTimeOut) { + StartDownload(1); + EXPECT_FALSE(success_); +} + +// Test that resumption succeeds if the download item is found and can be +// resumed. +TEST_F(DownloadManagerServiceTest, ResumptionWithResumableItem) { + CreateDownloadItem(true); + StartDownload(1); + EXPECT_TRUE(success_); +} + +// Test that resumption fails if the target download item is not resumable. +TEST_F(DownloadManagerServiceTest, ResumptionWithNonResumableItem) { + CreateDownloadItem(false); + StartDownload(1); + EXPECT_FALSE(success_); +}
diff --git a/chrome/browser/app_controller_mac_unittest.mm b/chrome/browser/app_controller_mac_unittest.mm index 5a9d8dd..bdc68a83 100644 --- a/chrome/browser/app_controller_mac_unittest.mm +++ b/chrome/browser/app_controller_mac_unittest.mm
@@ -125,7 +125,7 @@ SigninManager* signin = SigninManagerFactory::GetForProfile(profile_); signin->SetAuthenticatedAccountInfo(username, username); ProfileSyncService* sync = ProfileSyncServiceFactory::GetForProfile(profile_); - sync->SetSyncSetupCompleted(); + sync->SetFirstSetupComplete(); [AppController updateSigninItem:syncMenuItem shouldShow:YES currentProfile:profile_]; @@ -145,7 +145,7 @@ SigninManager* signin = SigninManagerFactory::GetForProfile(profile_); signin->SetAuthenticatedAccountInfo(username, username); ProfileSyncService* sync = ProfileSyncServiceFactory::GetForProfile(profile_); - sync->SetSyncSetupCompleted(); + sync->SetFirstSetupComplete(); // Force an auth error. FakeAuthStatusProvider provider( SigninErrorControllerFactory::GetForProfile(profile_));
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 8507606..bf34323 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -198,7 +198,7 @@ #include "chrome/installer/util/helper.h" #include "chrome/installer/util/install_util.h" #include "chrome/installer/util/shell_util.h" -#include "components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "net/base/net_util.h" #include "ui/base/l10n/l10n_util_win.h" #include "ui/gfx/win/dpi.h"
diff --git a/chrome/browser/domain_reliability/service_factory.cc b/chrome/browser/domain_reliability/service_factory.cc index 668194f..061a33e 100644 --- a/chrome/browser/domain_reliability/service_factory.cc +++ b/chrome/browser/domain_reliability/service_factory.cc
@@ -31,21 +31,6 @@ // Identifies Chrome as the source of Domain Reliability uploads it sends. const char kUploadReporterString[] = "chrome"; -bool IsDomainReliabilityMonitoringEnabled() { - base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDisableDomainReliability)) - return false; - if (command_line->HasSwitch(switches::kEnableDomainReliability)) - return true; - - if (base::FieldTrialList::TrialExists(kFieldTrialName)) { - std::string value = base::FieldTrialList::FindFullName(kFieldTrialName); - return value == kFieldTrialValueEnable; - } - - return kDefaultEnabled; -} - } // namespace // static @@ -72,14 +57,25 @@ KeyedService* DomainReliabilityServiceFactory::BuildServiceInstanceFor( content::BrowserContext* context) const { - if (!IsDomainReliabilityMonitoringEnabled()) - return NULL; - // TODO(ttuttle): Move this check closer to where the data gets sent - // crbug.com/533486 - if (!ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled()) + if (!ShouldCreateService()) return NULL; return DomainReliabilityService::Create(kUploadReporterString); } +bool DomainReliabilityServiceFactory::ShouldCreateService() const { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kDisableDomainReliability)) + return false; + if (command_line->HasSwitch(switches::kEnableDomainReliability)) + return true; + if (!ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled()) + return false; + if (base::FieldTrialList::TrialExists(kFieldTrialName)) { + std::string value = base::FieldTrialList::FindFullName(kFieldTrialName); + return (value == kFieldTrialValueEnable); + } + return kDefaultEnabled; +} + } // namespace domain_reliability
diff --git a/chrome/browser/domain_reliability/service_factory.h b/chrome/browser/domain_reliability/service_factory.h index bc90366..2a77b03 100644 --- a/chrome/browser/domain_reliability/service_factory.h +++ b/chrome/browser/domain_reliability/service_factory.h
@@ -37,6 +37,8 @@ KeyedService* BuildServiceInstanceFor( content::BrowserContext* context) const override; + bool ShouldCreateService() const; + DISALLOW_COPY_AND_ASSIGN(DomainReliabilityServiceFactory); };
diff --git a/chrome/browser/download/download_extensions.cc b/chrome/browser/download/download_extensions.cc index 12d0e4a5..dea28b0 100644 --- a/chrome/browser/download/download_extensions.cc +++ b/chrome/browser/download/download_extensions.cc
@@ -153,6 +153,7 @@ {"uu", NOT_DANGEROUS, ALLOW_AUTO_OPEN}, {"uue", NOT_DANGEROUS, ALLOW_AUTO_OPEN}, {"vhd", NOT_DANGEROUS, ALLOW_AUTO_OPEN}, + {"vhdx", NOT_DANGEROUS, ALLOW_AUTO_OPEN}, // Opens in IE, drops MOTW {"vmdk", NOT_DANGEROUS, ALLOW_AUTO_OPEN}, {"wim", NOT_DANGEROUS, ALLOW_AUTO_OPEN}, {"wrc", NOT_DANGEROUS, ALLOW_AUTO_OPEN},
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc index 861c7ad..a9a05d81 100644 --- a/chrome/browser/extensions/extension_service_sync_unittest.cc +++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -202,7 +202,7 @@ // The user has enabled sync. ProfileSyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(profile()); - sync_service->SetSyncSetupCompleted(); + sync_service->SetFirstSetupComplete(); service()->Init(); ASSERT_TRUE(service()->is_ready()); @@ -243,7 +243,7 @@ // The user has enabled sync. ProfileSyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(profile()); - sync_service->SetSyncSetupCompleted(); + sync_service->SetFirstSetupComplete(); // Make sure ExtensionSyncService is created, so it'll be notified of changes. extension_sync_service(); @@ -301,7 +301,7 @@ InitializeInstalledExtensionService(pref_path, source_install_dir); // The user has enabled sync. - ProfileSyncServiceFactory::GetForProfile(profile())->SetSyncSetupCompleted(); + ProfileSyncServiceFactory::GetForProfile(profile())->SetFirstSetupComplete(); // Make sure ExtensionSyncService is created, so it'll be notified of changes. extension_sync_service(); @@ -1417,7 +1417,7 @@ InitializeEmptyExtensionService(); // The user has enabled sync. - ProfileSyncServiceFactory::GetForProfile(profile())->SetSyncSetupCompleted(); + ProfileSyncServiceFactory::GetForProfile(profile())->SetFirstSetupComplete(); // Make sure ExtensionSyncService is created, so it'll be notified of changes. extension_sync_service();
diff --git a/chrome/browser/extensions/external_pref_loader.cc b/chrome/browser/extensions/external_pref_loader.cc index 1cd9e117..02d8ea75 100644 --- a/chrome/browser/extensions/external_pref_loader.cc +++ b/chrome/browser/extensions/external_pref_loader.cc
@@ -136,9 +136,8 @@ ProfileSyncService* service = ProfileSyncServiceFactory::GetForProfile(profile_); DCHECK(service); - if (service->CanSyncStart() && - (service->HasSyncSetupCompleted() || - browser_defaults::kSyncAutoStarts)) { + if (service->CanSyncStart() && (service->IsFirstSetupComplete() || + browser_defaults::kSyncAutoStarts)) { service->AddObserver(this); } else { PostLoadAndRemoveObservers();
diff --git a/chrome/browser/memory/tab_manager.cc b/chrome/browser/memory/tab_manager.cc index b52b63e8..405ea68 100644 --- a/chrome/browser/memory/tab_manager.cc +++ b/chrome/browser/memory/tab_manager.cc
@@ -27,6 +27,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/thread.h" +#include "base/time/tick_clock.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/memory/oom_memory_details.h" @@ -113,7 +114,8 @@ : discard_count_(0), recent_tab_discard_(false), discard_once_(false), - browser_tab_strip_tracker_(this, nullptr, nullptr) { + browser_tab_strip_tracker_(this, nullptr, nullptr), + test_tick_clock_(nullptr) { #if defined(OS_CHROMEOS) delegate_.reset(new TabManagerDelegate); #endif @@ -155,7 +157,7 @@ FROM_HERE, TimeDelta::FromSeconds(kRecentTabDiscardIntervalSeconds), this, &TabManager::RecordRecentTabDiscard); } - start_time_ = TimeTicks::Now(); + start_time_ = NowTicks(); // Create a |MemoryPressureListener| to listen for memory events. base::MemoryPressureMonitor* monitor = base::MemoryPressureMonitor::Get(); if (monitor) { @@ -251,6 +253,10 @@ OomMemoryDetails::Log(title, callback); } +void TabManager::set_test_tick_clock(base::TickClock* test_tick_clock) { + test_tick_clock_ = test_tick_clock; +} + void TabManager::TabChangedAt(content::WebContents* contents, int index, TabChangeType change_type) { @@ -261,7 +267,7 @@ bool current_state = contents->WasRecentlyAudible(); if (old_state != current_state) { data->SetRecentlyAudible(current_state); - data->SetLastAudioChangeTime(TimeTicks::Now()); + data->SetLastAudioChangeTime(NowTicks()); } } @@ -273,7 +279,7 @@ // If |old_contents| is set, that tab has switched from being active to // inactive, so record the time of that transition. if (old_contents) - GetWebContentsData(old_contents)->SetLastInactiveTime(TimeTicks::Now()); + GetWebContentsData(old_contents)->SetLastInactiveTime(NowTicks()); } /////////////////////////////////////////////////////////////////////////////// @@ -326,14 +332,14 @@ // Bin into <= 1, <= 2, <= 4, <= 8, etc. if (last_discard_time_.is_null()) { // This is the first discard this session. - TimeDelta interval = TimeTicks::Now() - start_time_; + TimeDelta interval = NowTicks() - start_time_; int interval_seconds = static_cast<int>(interval.InSeconds()); // Record time in seconds over an interval of approximately 1 day. UMA_HISTOGRAM_CUSTOM_COUNTS("Tabs.Discard.InitialTime2", interval_seconds, 1, 100000, 50); } else { // Not the first discard, so compute time since last discard. - TimeDelta interval = TimeTicks::Now() - last_discard_time_; + TimeDelta interval = NowTicks() - last_discard_time_; int interval_ms = static_cast<int>(interval.InMilliseconds()); // Record time in milliseconds over an interval of approximately 1 day. // Start at 100 ms to get extra resolution in the target 750 ms range. @@ -347,7 +353,7 @@ metrics::RecordMemoryStats(metrics::RECORD_MEMORY_STATS_TAB_DISCARDED); #endif // Set up to record the next interval. - last_discard_time_ = TimeTicks::Now(); + last_discard_time_ = NowTicks(); } void TabManager::RecordRecentTabDiscard() { @@ -442,7 +448,7 @@ // Check for a discontinuity in time caused by the machine being suspended. if (!last_adjust_time_.is_null()) { - TimeDelta suspend_time = TimeTicks::Now() - last_adjust_time_; + TimeDelta suspend_time = NowTicks() - last_adjust_time_; if (suspend_time.InSeconds() > kSuspendThresholdSeconds) { // System was probably suspended, move the event timers forward in time so // when they get subtracted out later, "uptime" is being counted. @@ -451,7 +457,7 @@ last_discard_time_ += suspend_time; } } - last_adjust_time_ = TimeTicks::Now(); + last_adjust_time_ = NowTicks(); #if defined(OS_CHROMEOS) TabStatsList stats_list = GetTabStats(); @@ -567,8 +573,7 @@ bool TabManager::IsAudioTab(WebContents* contents) const { if (contents->WasRecentlyAudible()) return true; - auto delta = - TimeTicks::Now() - GetWebContentsData(contents)->LastAudioChangeTime(); + auto delta = NowTicks() - GetWebContentsData(contents)->LastAudioChangeTime(); return delta < TimeDelta::FromSeconds(kAudioProtectionTimeSeconds); } @@ -618,4 +623,11 @@ return first.last_active > second.last_active; } +TimeTicks TabManager::NowTicks() const { + if (!test_tick_clock_) + return TimeTicks::Now(); + + return test_tick_clock_->NowTicks(); +} + } // namespace memory
diff --git a/chrome/browser/memory/tab_manager.h b/chrome/browser/memory/tab_manager.h index fabdd33d..2e93f3bb 100644 --- a/chrome/browser/memory/tab_manager.h +++ b/chrome/browser/memory/tab_manager.h
@@ -25,6 +25,10 @@ class BrowserList; class GURL; +namespace base { +class TickClock; +} + namespace content { class WebContents; } @@ -95,6 +99,10 @@ // Log memory statistics for the running processes, then call the callback. void LogMemory(const std::string& title, const base::Closure& callback); + // Used to set the test TickClock, which then gets used by NowTicks(). See + // |test_tick_clock_| for more details. + void set_test_tick_clock(base::TickClock* test_tick_clock); + private: FRIEND_TEST_ALL_PREFIXES(TabManagerTest, Comparator); FRIEND_TEST_ALL_PREFIXES(TabManagerTest, DiscardedTabKeepsLastActiveTime); @@ -169,6 +177,10 @@ // |second|. static bool CompareTabStats(TabStats first, TabStats second); + // Returns either the system's clock or the test clock. See |test_tick_clock_| + // for more details. + base::TimeTicks NowTicks() const; + // Timer to periodically update the stats of the renderers. base::RepeatingTimer update_timer_; @@ -206,6 +218,10 @@ BrowserTabStripTracker browser_tab_strip_tracker_; + // Pointer to a test clock. If this is set, NowTicks() returns the value of + // this test clock. Otherwise it returns the system clock's value. + base::TickClock* test_tick_clock_; + DISALLOW_COPY_AND_ASSIGN(TabManager); };
diff --git a/chrome/browser/memory/tab_manager_web_contents_data.cc b/chrome/browser/memory/tab_manager_web_contents_data.cc index 4338a21..e7ab158 100644 --- a/chrome/browser/memory/tab_manager_web_contents_data.cc +++ b/chrome/browser/memory/tab_manager_web_contents_data.cc
@@ -129,7 +129,7 @@ test_tick_clock_ = test_tick_clock; } -TimeTicks TabManager::WebContentsData::NowTicks() { +TimeTicks TabManager::WebContentsData::NowTicks() const { if (!test_tick_clock_) return TimeTicks::Now();
diff --git a/chrome/browser/memory/tab_manager_web_contents_data.h b/chrome/browser/memory/tab_manager_web_contents_data.h index caf1a917..ee60a944 100644 --- a/chrome/browser/memory/tab_manager_web_contents_data.h +++ b/chrome/browser/memory/tab_manager_web_contents_data.h
@@ -100,7 +100,7 @@ // Returns either the system's clock or the test clock. See |test_tick_clock_| // for more details. - base::TimeTicks NowTicks(); + base::TimeTicks NowTicks() const; // Contains all the needed data for the tab. Data tab_data_;
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc index d98cfe47..d980cd98 100644 --- a/chrome/browser/metrics/chrome_metrics_service_client.cc +++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -76,6 +76,7 @@ #if defined(OS_WIN) #include <windows.h> #include "chrome/browser/metrics/google_update_metrics_provider_win.h" +#include "chrome/installer/util/browser_distribution.h" #include "components/browser_watcher/watcher_metrics_provider_win.h" #endif @@ -280,7 +281,8 @@ base::string16 ChromeMetricsServiceClient::GetRegistryBackupKey() { #if defined(OS_WIN) - return L"Software\\" PRODUCT_STRING_PATH L"\\StabilityMetrics"; + BrowserDistribution* distribution = BrowserDistribution::GetDistribution(); + return distribution->GetRegistryPath().append(L"\\StabilityMetrics"); #else return base::string16(); #endif
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc index 000060f..cb356c9c 100644 --- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc +++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -190,7 +190,7 @@ syncer::ModelTypeSet active_types; active_types.Put(syncer::PASSWORDS); - EXPECT_CALL(*mock_sync_service, HasSyncSetupCompleted()) + EXPECT_CALL(*mock_sync_service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*mock_sync_service, IsSyncActive()).WillRepeatedly(Return(true)); EXPECT_CALL(*mock_sync_service, GetActiveDataTypes())
diff --git a/chrome/browser/profiles/profile_destroyer.cc b/chrome/browser/profiles/profile_destroyer.cc index 809703f..4dbb1a8 100644 --- a/chrome/browser/profiles/profile_destroyer.cc +++ b/chrome/browser/profiles/profile_destroyer.cc
@@ -122,12 +122,13 @@ if (profile_) DestroyProfileWhenAppropriate(profile_); +#ifdef NDEBUG // Don't wait for pending registrations, if any, these hosts are buggy. // Note: this can happen, but if so, it's better to crash here than wait // for the host to dereference a deleted Profile. http://crbug.com/248625 CHECK_EQ(0U, num_hosts_) << "Some render process hosts were not " << "destroyed early enough!"; - +#endif // NDEBUG DCHECK(pending_destroyers_ != NULL); DestroyerSet::iterator iter = pending_destroyers_->find(this); DCHECK(iter != pending_destroyers_->end());
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js index c01b6d2..a351f811 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors.js
@@ -411,14 +411,14 @@ */ move: function(unit, dir) { var newStart = this.start_; - var newEnd = newStart; + var newEnd; switch (unit) { case Unit.CHARACTER: newStart = newStart.move(unit, Movement.BOUND, dir); newEnd = newStart.move(unit, Movement.BOUND, Dir.FORWARD); // Character crossed a node; collapses to the end of the node. if (newStart.node !== newEnd.node) - newEnd = newStart; + newEnd = new cursors.Cursor(newStart.node, newStart.index + 1); break; case Unit.WORD: case Unit.LINE: @@ -431,6 +431,8 @@ newStart = newStart.move(unit, Movement.DIRECTIONAL, dir); newEnd = newStart; break; + default: + throw Error('Invalid unit: ' + unit); } return new cursors.Range(newStart, newEnd); },
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs index ced8459f..b33f3be 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/cursors_test.extjs
@@ -213,13 +213,13 @@ [CHARACTER, FORWARD, {value: 'start ', index: 4}, {value: 'start ', index: 5}], [CHARACTER, FORWARD, - {value: 'start ', index: 5}, {value: 'start ', index: 5}], + {value: 'start ', index: 5}, {value: 'start ', index: 6}], [CHARACTER, FORWARD, {value: 'same line', index: 0}, {value: 'same line', index: 1}], [CHARACTER, BACKWARD, - {value: 'start ', index: 5}, {value: 'start ', index: 5}], + {value: 'start ', index: 5}, {value: 'start ', index: 6}], [CHARACTER, BACKWARD, {value: 'start ', index: 4}, {value: 'start ', index: 5}], [CHARACTER, BACKWARD,
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js index ce0d7e55..611e24b3 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/output.js
@@ -1258,8 +1258,6 @@ {stay: true, name: true, value: true}); var startIndex = range.start.index; var endIndex = range.end.index; - if (startIndex === endIndex) - endIndex++; this.append_( buff, range.start.getText().substring(startIndex, endIndex)); this.locations_.push(
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc index f56103ff..4d04f67 100644 --- a/chrome/browser/safe_browsing/protocol_manager.cc +++ b/chrome/browser/safe_browsing/protocol_manager.cc
@@ -444,6 +444,8 @@ if (it != hash_requests_.end()) { // GetHash response. + // Reset the scoped pointer so the fetcher gets destroyed properly. + fetcher.reset(it->first); RecordHttpResponseOrErrorCode(kGetHashUmaResponseMetricName, status, response_code); const FullHashDetails& details = it->second; @@ -492,6 +494,9 @@ // V4 FindFullHashes response. // TODO(kcarattini): Consider pulling all the V4 handling out into a // separate V4ProtocolManager class. + + // Reset the scoped pointer so the fetcher gets destroyed properly. + fetcher.reset(v4_it->first); RecordHttpResponseOrErrorCode(kUmaV4ResponseMetricName, status, response_code); const FullHashDetails& details = v4_it->second;
diff --git a/chrome/browser/safe_browsing/protocol_manager.h b/chrome/browser/safe_browsing/protocol_manager.h index 8d3c1191..c50ac2a8 100644 --- a/chrome/browser/safe_browsing/protocol_manager.h +++ b/chrome/browser/safe_browsing/protocol_manager.h
@@ -224,6 +224,12 @@ TestGetHashBackOffTimes); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestGetV4HashBackOffTimes); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, + TestGetV4HashErrorHandlingOK); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, + TestGetV4HashErrorHandlingNetwork); + FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, + TestGetV4HashErrorHandlingResponseCode); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestNextChunkUrl); FRIEND_TEST_ALL_PREFIXES(SafeBrowsingProtocolManagerTest, TestUpdateUrl); friend class SafeBrowsingServerTest;
diff --git a/chrome/browser/safe_browsing/protocol_manager_unittest.cc b/chrome/browser/safe_browsing/protocol_manager_unittest.cc index b670f51a..87b8dff 100644 --- a/chrome/browser/safe_browsing/protocol_manager_unittest.cc +++ b/chrome/browser/safe_browsing/protocol_manager_unittest.cc
@@ -122,8 +122,128 @@ EXPECT_EQ("", url_fetcher->upload_data()); EXPECT_EQ(GURL(expected_url), url_fetcher->GetOriginalURL()); } + + std::string GetStockV4HashResponse() { + FindFullHashesResponse res; + res.mutable_negative_cache_duration()->set_seconds(600); + ThreatMatch* m = res.add_matches(); + m->set_threat_type(API_ABUSE); + m->set_platform_type(CHROME_PLATFORM); + m->set_threat_entry_type(URL_EXPRESSION); + m->mutable_cache_duration()->set_seconds(300); + m->mutable_threat()->set_hash(SBFullHashToString( + SBFullHashForString("Everything's shiny, Cap'n."))); + ThreatEntryMetadata::MetadataEntry* e = + m->mutable_threat_entry_metadata()->add_entries(); + e->set_key("permission"); + e->set_value("NOTIFICATIONS"); + + // Serialize. + std::string res_data; + res.SerializeToString(&res_data); + + return res_data; + } }; +void ValidateGetV4HashResults( + const std::vector<SBFullHashResult>& expected_full_hashes, + const base::TimeDelta& expected_cache_duration, + const std::vector<SBFullHashResult>& full_hashes, + const base::TimeDelta& cache_duration) { + EXPECT_EQ(expected_cache_duration, cache_duration); + ASSERT_EQ(expected_full_hashes.size(), full_hashes.size()); + + for (unsigned int i = 0; i < expected_full_hashes.size(); ++i) { + const SBFullHashResult& expected = expected_full_hashes[i]; + const SBFullHashResult& actual = full_hashes[i]; + EXPECT_TRUE(SBFullHashEqual(expected.hash, actual.hash)); + EXPECT_EQ(expected.metadata, actual.metadata); + EXPECT_EQ(expected.cache_duration, actual.cache_duration); + } +} + +TEST_F(SafeBrowsingProtocolManagerTest, TestGetV4HashErrorHandlingNetwork) { + net::TestURLFetcherFactory factory; + scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL)); + + std::vector<SBPrefix> prefixes; + std::vector<SBFullHashResult> expected_full_hashes; + base::TimeDelta expected_cache_duration; + + pm->GetFullHashesWithApis(prefixes, + base::Bind(&ValidateGetV4HashResults, + expected_full_hashes, expected_cache_duration)); + + net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); + DCHECK(fetcher); + // Failed request status should result in error. + fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED, + net::ERR_CONNECTION_RESET)); + fetcher->set_response_code(200); + fetcher->SetResponseString(GetStockV4HashResponse()); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + // Should have recorded one error, but back off multiplier is unchanged. + EXPECT_EQ(1ul, pm->gethash_v4_error_count_); + EXPECT_EQ(1ul, pm->gethash_v4_back_off_mult_); +} + +TEST_F(SafeBrowsingProtocolManagerTest, + TestGetV4HashErrorHandlingResponseCode) { + net::TestURLFetcherFactory factory; + scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL)); + + std::vector<SBPrefix> prefixes; + std::vector<SBFullHashResult> expected_full_hashes; + base::TimeDelta expected_cache_duration; + + pm->GetFullHashesWithApis(prefixes, + base::Bind(&ValidateGetV4HashResults, + expected_full_hashes, expected_cache_duration)); + + net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); + DCHECK(fetcher); + fetcher->set_status(net::URLRequestStatus()); + // Response code of anything other than 200 should result in error. + fetcher->set_response_code(204); + fetcher->SetResponseString(GetStockV4HashResponse()); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + // Should have recorded one error, but back off multiplier is unchanged. + EXPECT_EQ(1ul, pm->gethash_v4_error_count_); + EXPECT_EQ(1ul, pm->gethash_v4_back_off_mult_); +} + +TEST_F(SafeBrowsingProtocolManagerTest, TestGetV4HashErrorHandlingOK) { + net::TestURLFetcherFactory factory; + scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL)); + + std::vector<SBPrefix> prefixes; + std::vector<SBFullHashResult> expected_full_hashes; + SBFullHashResult hash_result; + hash_result.hash = SBFullHashForString("Everything's shiny, Cap'n."); + hash_result.metadata = "NOTIFICATIONS,"; + hash_result.cache_duration = base::TimeDelta::FromSeconds(300); + expected_full_hashes.push_back(hash_result); + base::TimeDelta expected_cache_duration = base::TimeDelta::FromSeconds(600); + + pm->GetFullHashesWithApis(prefixes, + base::Bind(&ValidateGetV4HashResults, + expected_full_hashes, expected_cache_duration)); + + net::TestURLFetcher* fetcher = factory.GetFetcherByID(0); + DCHECK(fetcher); + fetcher->set_status(net::URLRequestStatus()); + fetcher->set_response_code(200); + fetcher->SetResponseString(GetStockV4HashResponse()); + fetcher->delegate()->OnURLFetchComplete(fetcher); + + // No error, back off multiplier is unchanged. + EXPECT_EQ(0ul, pm->gethash_v4_error_count_); + EXPECT_EQ(1ul, pm->gethash_v4_back_off_mult_); +} + // Ensure that we respect section 5 of the SafeBrowsing protocol specification. TEST_F(SafeBrowsingProtocolManagerTest, TestBackOffTimes) { scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc index 37045a6..0e2c788 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -225,6 +225,11 @@ return std::string(); } +std::string MutableProfileOAuth2TokenServiceDelegate::GetRefreshTokenForTest( + const std::string& account_id) const { + return GetRefreshToken(account_id); +} + std::vector<std::string> MutableProfileOAuth2TokenServiceDelegate::GetAccounts() { std::vector<std::string> account_ids;
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h index 0353fc4..39768ba 100644 --- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h +++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
@@ -62,6 +62,9 @@ // Overridden from OAuth2TokenServiceDelegate. const net::BackoffEntry* BackoffEntry() const override; + // Returns the account's refresh token used for testing purposes. + std::string GetRefreshTokenForTest(const std::string& account_id) const; + private: friend class MutableProfileOAuth2TokenServiceDelegateTest;
diff --git a/chrome/browser/signin/token_revoker_test_utils.cc b/chrome/browser/signin/token_revoker_test_utils.cc new file mode 100644 index 0000000..25add2de --- /dev/null +++ b/chrome/browser/signin/token_revoker_test_utils.cc
@@ -0,0 +1,34 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/signin/token_revoker_test_utils.h" +#include "content/public/test/test_utils.h" +#include "google_apis/gaia/gaia_auth_fetcher.h" +#include "google_apis/gaia/gaia_constants.h" + +namespace token_revoker_test_utils { + +RefreshTokenRevoker::RefreshTokenRevoker() + : gaia_fetcher_(this, + GaiaConstants::kChromeSource, + g_browser_process->system_request_context()) { +} + +RefreshTokenRevoker::~RefreshTokenRevoker() { +} + +void RefreshTokenRevoker::Revoke(const std::string& token) { + DVLOG(1) << "Starting RefreshTokenRevoker for token: " << token; + gaia_fetcher_.StartRevokeOAuth2Token(token); + message_loop_runner_ = new content::MessageLoopRunner; + message_loop_runner_->Run(); +} + +void RefreshTokenRevoker::OnOAuth2RevokeTokenCompleted() { + DVLOG(1) << "TokenRevoker OnOAuth2RevokeTokenCompleted"; + message_loop_runner_->Quit(); +} + +} // namespace token_revoker_test_utils
diff --git a/chrome/browser/signin/token_revoker_test_utils.h b/chrome/browser/signin/token_revoker_test_utils.h new file mode 100644 index 0000000..b8705c7 --- /dev/null +++ b/chrome/browser/signin/token_revoker_test_utils.h
@@ -0,0 +1,39 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SIGNIN_TOKEN_REVOKER_TEST_UTILS_H_ +#define CHROME_BROWSER_SIGNIN_TOKEN_REVOKER_TEST_UTILS_H_ + +#include "base/memory/ref_counted.h" +#include "google_apis/gaia/gaia_auth_fetcher.h" + +namespace content { +class MessageLoopRunner; +} + +namespace token_revoker_test_utils { + +// A helper class that takes care of asynchronously revoking a refresh token. +class RefreshTokenRevoker : public GaiaAuthConsumer { + public: + RefreshTokenRevoker(); + ~RefreshTokenRevoker() override; + + // Sends a request to Gaia servers to revoke the refresh token. Blocks until + // it is revoked, i.e. until OnOAuth2RevokeTokenCompleted is fired. + void Revoke(const std::string& token); + + // Called when token is revoked. + void OnOAuth2RevokeTokenCompleted() override; + + private: + GaiaAuthFetcher gaia_fetcher_; + scoped_refptr<content::MessageLoopRunner> message_loop_runner_; + + DISALLOW_COPY_AND_ASSIGN(RefreshTokenRevoker); +}; + +} // namespace token_revoker_test_utils + +#endif // CHROME_BROWSER_SIGNIN_TOKEN_REVOKER_TEST_UTILS_H_
diff --git a/chrome/browser/supervised_user/child_accounts/child_account_service.cc b/chrome/browser/supervised_user/child_accounts/child_account_service.cc index b6d9889..6bdcb0a 100644 --- a/chrome/browser/supervised_user/child_accounts/child_account_service.cc +++ b/chrome/browser/supervised_user/child_accounts/child_account_service.cc
@@ -184,7 +184,7 @@ // The logic to do this lives in the SupervisedUserSyncDataTypeController. ProfileSyncService* sync_service = ProfileSyncServiceFactory::GetForProfile(profile_); - if (sync_service->HasSyncSetupCompleted()) + if (sync_service->IsFirstSetupComplete()) sync_service->ReconfigureDatatypeManager(); return true;
diff --git a/chrome/browser/supervised_user/supervised_user_service.cc b/chrome/browser/supervised_user/supervised_user_service.cc index 7ecdd88b..1f3f51e 100644 --- a/chrome/browser/supervised_user/supervised_user_service.cc +++ b/chrome/browser/supervised_user/supervised_user_service.cc
@@ -696,7 +696,7 @@ // Notify ProfileSyncService that we are done with configuration. service->SetSetupInProgress(false); - service->SetSyncSetupCompleted(); + service->SetFirstSetupComplete(); } #endif
diff --git a/chrome/browser/sync/profile_sync_service_android.cc b/chrome/browser/sync/profile_sync_service_android.cc index b24aa78b3..5889c34 100644 --- a/chrome/browser/sync/profile_sync_service_android.cc +++ b/chrome/browser/sync/profile_sync_service_android.cc
@@ -187,18 +187,18 @@ sync_service_->SetSetupInProgress(in_progress); } -jboolean ProfileSyncServiceAndroid::HasSyncSetupCompleted( +jboolean ProfileSyncServiceAndroid::IsFirstSetupComplete( JNIEnv* env, const JavaParamRef<jobject>& obj) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - return sync_service_->HasSyncSetupCompleted(); + return sync_service_->IsFirstSetupComplete(); } -void ProfileSyncServiceAndroid::SetSyncSetupCompleted( +void ProfileSyncServiceAndroid::SetFirstSetupComplete( JNIEnv* env, const JavaParamRef<jobject>& obj) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - sync_service_->SetSyncSetupCompleted(); + sync_service_->SetFirstSetupComplete(); } ScopedJavaLocalRef<jintArray> ProfileSyncServiceAndroid::GetActiveDataTypes(
diff --git a/chrome/browser/sync/profile_sync_service_android.h b/chrome/browser/sync/profile_sync_service_android.h index c69e78e7f..9be8bee 100644 --- a/chrome/browser/sync/profile_sync_service_android.h +++ b/chrome/browser/sync/profile_sync_service_android.h
@@ -57,10 +57,10 @@ void SetSetupInProgress(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj, jboolean in_progress); - jboolean HasSyncSetupCompleted( + jboolean IsFirstSetupComplete( JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); - void SetSyncSetupCompleted(JNIEnv* env, + void SetFirstSetupComplete(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj); base::android::ScopedJavaLocalRef<jintArray> GetActiveDataTypes( JNIEnv* env,
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc index 0f59dc6..2876157 100644 --- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc +++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -280,7 +280,7 @@ TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) { // We've never completed startup. - profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted); + profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete); CreateSyncService(); SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); @@ -296,7 +296,7 @@ 0, profile_->GetPrefs()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime)); EXPECT_FALSE(profile_->GetPrefs()->GetBoolean( - sync_driver::prefs::kSyncHasSetupCompleted)); + sync_driver::prefs::kSyncFirstSetupComplete)); Mock::VerifyAndClearExpectations(data_type_manager); // Then start things up. @@ -323,7 +323,7 @@ // TODO(pavely): Reenable test once android is switched to oauth2. TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartNoCredentials) { // We've never completed startup. - profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted); + profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete); CreateSyncService(); // Should not actually start, rather just clean things up and wait @@ -339,7 +339,7 @@ 0, profile_->GetPrefs()->GetInt64(sync_driver::prefs::kSyncLastSyncedTime)); EXPECT_FALSE(profile_->GetPrefs()->GetBoolean( - sync_driver::prefs::kSyncHasSetupCompleted)); + sync_driver::prefs::kSyncFirstSetupComplete)); // Then start things up. sync_->SetSetupInProgress(true); @@ -403,7 +403,7 @@ EXPECT_CALL(*GetSyncApiComponentFactoryMock(), CreateSyncBackendHost(_, _, _, _)) .Times(0); - profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted); + profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); sync_->Initialize(); @@ -418,7 +418,7 @@ TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) { SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); - profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted); + profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete); EXPECT_CALL(*data_type_manager, Configure(_, _)); EXPECT_CALL(*data_type_manager, state()). WillRepeatedly(Return(DataTypeManager::CONFIGURED)); @@ -437,7 +437,7 @@ CreateSyncService(); std::string account_id = SimulateTestUserSignin(profile_, fake_signin(), sync_); - sync_->SetSyncSetupCompleted(); + sync_->SetFirstSetupComplete(); SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_, _)); @@ -469,7 +469,7 @@ CreateSyncService(); std::string account_id = SimulateTestUserSignin(profile_, fake_signin(), sync_); - sync_->SetSyncSetupCompleted(); + sync_->SetFirstSetupComplete(); SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_, _)); @@ -497,7 +497,7 @@ CreateSyncService(); std::string account_id = SimulateTestUserSignin(profile_, fake_signin(), sync_); - sync_->SetSyncSetupCompleted(); + sync_->SetFirstSetupComplete(); SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_, _)); @@ -532,7 +532,7 @@ CreateSyncService(); std::string account_id = SimulateTestUserSignin(profile_, fake_signin(), sync_); - sync_->SetSyncSetupCompleted(); + sync_->SetFirstSetupComplete(); SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); EXPECT_CALL(*data_type_manager, Configure(_, _)); @@ -549,7 +549,8 @@ profile_->GetPrefs()->SetBoolean(sync_driver::prefs::kSyncManaged, true); // When switching back to unmanaged, the state should change, but the service - // should not start up automatically (kSyncSetupCompleted will be false). + // should not start up automatically (kSyncFirstSetupComplete will be + // false). Mock::VerifyAndClearExpectations(data_type_manager); EXPECT_CALL(*GetSyncApiComponentFactoryMock(), CreateDataTypeManager(_, _, _, _, _)) @@ -562,7 +563,7 @@ CreateSyncService(); std::string account_id = SimulateTestUserSignin(profile_, fake_signin(), sync_); - sync_->SetSyncSetupCompleted(); + sync_->SetFirstSetupComplete(); SetUpSyncBackendHost(); DataTypeManagerMock* data_type_manager = SetUpDataTypeManager(); DataTypeManager::ConfigureStatus status = DataTypeManager::ABORTED; @@ -592,7 +593,7 @@ SyncBackendHostMock* mock_sbh = SetUpSyncBackendHost(); mock_sbh->set_fail_initial_download(true); - profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted); + profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncFirstSetupComplete); EXPECT_CALL(observer_, OnStateChanged()).Times(AnyNumber()); sync_->Initialize();
diff --git a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc index 90e3571..03c0f01 100644 --- a/chrome/browser/sync/sync_error_notifier_ash_unittest.cc +++ b/chrome/browser/sync/sync_error_notifier_ash_unittest.cc
@@ -152,8 +152,8 @@ void VerifySyncErrorNotifierResult(GoogleServiceAuthError::State error_state, bool is_signed_in, bool is_error) { - EXPECT_CALL(*service_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(is_signed_in)); + EXPECT_CALL(*service_, IsFirstSetupComplete()) + .WillRepeatedly(Return(is_signed_in)); GoogleServiceAuthError auth_error(error_state); EXPECT_CALL(*service_, GetAuthError()).WillRepeatedly(
diff --git a/chrome/browser/sync/sync_global_error_unittest.cc b/chrome/browser/sync/sync_global_error_unittest.cc index ae20eaaa..d35c0af 100644 --- a/chrome/browser/sync/sync_global_error_unittest.cc +++ b/chrome/browser/sync/sync_global_error_unittest.cc
@@ -86,8 +86,8 @@ GoogleServiceAuthError::State error_state, bool is_signed_in, bool is_error) { - EXPECT_CALL(*service, HasSyncSetupCompleted()) - .WillRepeatedly(Return(is_signed_in)); + EXPECT_CALL(*service, IsFirstSetupComplete()) + .WillRepeatedly(Return(is_signed_in)); GoogleServiceAuthError auth_error(error_state); EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error));
diff --git a/chrome/browser/sync/sync_ui_util.cc b/chrome/browser/sync/sync_ui_util.cc index e1feffb9..8a38e6c 100644 --- a/chrome/browser/sync/sync_ui_util.cc +++ b/chrome/browser/sync/sync_ui_util.cc
@@ -159,7 +159,7 @@ if (!signin.IsAuthenticated()) return PRE_SYNCED; - if (!service || service->IsManaged() || service->HasSyncSetupCompleted() || + if (!service || service->IsManaged() || service->IsFirstSetupComplete() || !service->IsSyncRequested()) { // The order or priority is going to be: 1. Unrecoverable errors. // 2. Auth errors. 3. Protocol errors. 4. Passphrase errors. @@ -303,8 +303,7 @@ DCHECK(status_label); DCHECK(link_label); - if (service->HasSyncSetupCompleted() && - service->IsPassphraseRequired()) { + if (service->IsFirstSetupComplete() && service->IsPassphraseRequired()) { if (service->passphrase_required_reason() == syncer::REASON_ENCRYPTION) { // First machine migrating to passwords. Show as a promotion. if (status_label && link_label) { @@ -371,7 +370,7 @@ *bubble_accept_label = base::string16(); // Only display an error if we've completed sync setup. - if (!service->HasSyncSetupCompleted()) + if (!service->IsFirstSetupComplete()) return; // Display a passphrase error if we have one.
diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc index 7d4672b..4cb7724 100644 --- a/chrome/browser/sync/sync_ui_util_unittest.cc +++ b/chrome/browser/sync/sync_ui_util_unittest.cc
@@ -61,8 +61,8 @@ GoogleServiceAuthError::State error_state, bool is_signed_in, bool is_error) { - EXPECT_CALL(*service, HasSyncSetupCompleted()) - .WillRepeatedly(Return(is_signed_in)); + EXPECT_CALL(*service, IsFirstSetupComplete()) + .WillRepeatedly(Return(is_signed_in)); GoogleServiceAuthError auth_error(error_state); EXPECT_CALL(*service, GetAuthError()).WillRepeatedly(ReturnRef(auth_error)); @@ -118,8 +118,7 @@ .WillRepeatedly(Return(true)); EXPECT_CALL(service, IsPassphraseRequiredForDecryption()) .WillRepeatedly(Return(true)); - EXPECT_CALL(service, HasSyncSetupCompleted()) - .WillRepeatedly(Return(true)); + EXPECT_CALL(service, IsFirstSetupComplete()).WillRepeatedly(Return(true)); GoogleServiceAuthError auth_error( GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); @@ -216,7 +215,7 @@ // immutable so can only be allocated in this method. switch (caseNumber) { case STATUS_CASE_SETUP_IN_PROGRESS: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(false)); EXPECT_CALL(*service, IsFirstSetupInProgress()) .WillRepeatedly(Return(true)); @@ -226,7 +225,7 @@ return; } case STATUS_CASE_SETUP_ERROR: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(false)); EXPECT_CALL(*service, IsFirstSetupInProgress()) .WillRepeatedly(Return(false)); @@ -238,7 +237,7 @@ return; } case STATUS_CASE_AUTHENTICATING: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsPassphraseRequired()) @@ -252,7 +251,7 @@ return; } case STATUS_CASE_AUTH_ERROR: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsPassphraseRequired()) @@ -268,7 +267,7 @@ return; } case STATUS_CASE_PROTOCOL_ERROR: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsPassphraseRequired()) @@ -284,7 +283,7 @@ return; } case STATUS_CASE_PASSPHRASE_ERROR: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); browser_sync::SyncBackendHost::Status status; @@ -299,7 +298,7 @@ return; } case STATUS_CASE_SYNCED: { - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(true)); EXPECT_CALL(*service, IsPassphraseRequired()) @@ -315,7 +314,7 @@ } case STATUS_CASE_SYNC_DISABLED_BY_POLICY: { EXPECT_CALL(*service, IsManaged()).WillRepeatedly(Return(true)); - EXPECT_CALL(*service, HasSyncSetupCompleted()) + EXPECT_CALL(*service, IsFirstSetupComplete()) .WillRepeatedly(Return(false)); EXPECT_CALL(*service, IsSyncActive()).WillRepeatedly(Return(false)); EXPECT_CALL(*service, IsPassphraseRequired())
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc index ee7bf42..b0fef5f 100644 --- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc +++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -304,13 +304,12 @@ } bool ProfileSyncServiceHarness::IsSyncDisabled() const { - return !service()->IsSetupInProgress() && - !service()->HasSyncSetupCompleted(); + return !service()->IsSetupInProgress() && !service()->IsFirstSetupComplete(); } void ProfileSyncServiceHarness::FinishSyncSetup() { service()->SetSetupInProgress(false); - service()->SetSyncSetupCompleted(); + service()->SetFirstSetupComplete(); } SyncSessionSnapshot ProfileSyncServiceHarness::GetLastSessionSnapshot() const {
diff --git a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc index ba5be16..6d3325c 100644 --- a/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc +++ b/chrome/browser/sync/test/integration/quiesce_status_change_checker.cc
@@ -17,7 +17,7 @@ // Returns true if this service is disabled. bool IsSyncDisabled(ProfileSyncService* service) { - return !service->IsSetupInProgress() && !service->HasSyncSetupCompleted(); + return !service->IsSetupInProgress() && !service->IsFirstSetupComplete(); } // Returns true if these services have matching progress markers.
diff --git a/chrome/browser/sync/test/integration/sync_errors_test.cc b/chrome/browser/sync/test/integration/sync_errors_test.cc index 704f106b..fa204fc 100644 --- a/chrome/browser/sync/test/integration/sync_errors_test.cc +++ b/chrome/browser/sync/test/integration/sync_errors_test.cc
@@ -32,7 +32,7 @@ bool IsExitConditionSatisfied() override { return !service()->IsSetupInProgress() && - !service()->HasSyncSetupCompleted(); + !service()->IsFirstSetupComplete(); } std::string GetDebugMessage() const override { return "Sync Disabled"; }
diff --git a/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc b/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc index 423ba63..d625d03 100644 --- a/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_passwords_sync_test.cc
@@ -162,7 +162,7 @@ ASSERT_TRUE(AwaitPassphraseAccepted(GetSyncService(1))); // For some reason, the tests won't pass unless these flags are set. - GetSyncService(1)->SetSyncSetupCompleted(); + GetSyncService(1)->SetFirstSetupComplete(); GetSyncService(1)->SetSetupInProgress(false); // Move around some passwords to make sure it's all working.
diff --git a/chrome/browser/sync/test_profile_sync_service.cc b/chrome/browser/sync/test_profile_sync_service.cc index bef1b3d..1d2c8282 100644 --- a/chrome/browser/sync/test_profile_sync_service.cc +++ b/chrome/browser/sync/test_profile_sync_service.cc
@@ -153,7 +153,7 @@ static_cast<browser_sync::ChromeSyncClient*>(GetSyncClient()) ->SetSyncApiComponentFactoryForTesting( make_scoped_ptr(new SyncApiComponentFactoryMock)); - SetSyncSetupCompleted(); + SetFirstSetupComplete(); } TestProfileSyncService::~TestProfileSyncService() {
diff --git a/chrome/browser/sync_file_system/sync_file_system_service.cc b/chrome/browser/sync_file_system/sync_file_system_service.cc index 85d6f333..bfffa6a 100644 --- a/chrome/browser/sync_file_system/sync_file_system_service.cc +++ b/chrome/browser/sync_file_system/sync_file_system_service.cc
@@ -746,7 +746,7 @@ void SyncFileSystemService::UpdateSyncEnabledStatus( sync_driver::SyncService* profile_sync_service) { - if (!profile_sync_service->HasSyncSetupCompleted()) + if (!profile_sync_service->IsFirstSetupComplete()) return; bool old_sync_enabled = sync_enabled_; sync_enabled_ = profile_sync_service->GetActiveDataTypes().Has(
diff --git a/chrome/browser/ui/ash/app_sync_ui_state.cc b/chrome/browser/ui/ash/app_sync_ui_state.cc index 9ff5dc0..e519c31 100644 --- a/chrome/browser/ui/ash/app_sync_ui_state.cc +++ b/chrome/browser/ui/ash/app_sync_ui_state.cc
@@ -122,7 +122,7 @@ } void AppSyncUIState::CheckAppSync() { - if (!sync_service_ || !sync_service_->HasSyncSetupCompleted()) + if (!sync_service_ || !sync_service_->IsFirstSetupComplete()) return; const bool synced = sync_service_->IsSyncActive();
diff --git a/chrome/browser/ui/passwords/OWNERS b/chrome/browser/ui/passwords/OWNERS index 75a4ab7c..2c5da5ec3 100644 --- a/chrome/browser/ui/passwords/OWNERS +++ b/chrome/browser/ui/passwords/OWNERS
@@ -1,4 +1,2 @@ -markusheintz@chromium.org -mkwst@chromium.org vabr@chromium.org vasilii@chromium.org
diff --git a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc index 6fceb419..d9d6236 100644 --- a/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc +++ b/chrome/browser/ui/passwords/manage_passwords_bubble_model_unittest.cc
@@ -54,7 +54,7 @@ ~TestSyncService() override {} // FakeSyncService: - bool HasSyncSetupCompleted() const override { return true; } + bool IsFirstSetupComplete() const override { return true; } bool IsSyncAllowed() const override { return true; } bool IsSyncActive() const override { return true; } syncer::ModelTypeSet GetActiveDataTypes() const override {
diff --git a/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc b/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc index cb63bbd..d60e4f1 100644 --- a/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc +++ b/chrome/browser/ui/passwords/manage_passwords_view_utils_desktop_unittest.cc
@@ -74,7 +74,7 @@ ProfileSyncServiceMock* sync_service = static_cast<ProfileSyncServiceMock*>( ProfileSyncServiceFactory::GetInstance()->GetForProfile(&profile_)); EXPECT_CALL(*sync_service, IsSyncActive()).WillRepeatedly(Return(true)); - EXPECT_CALL(*sync_service, HasSyncSetupCompleted()) + EXPECT_CALL(*sync_service, IsFirstSetupComplete()) .WillRepeatedly(Return(true)); EXPECT_CALL(*sync_service, GetActiveDataTypes()) .WillRepeatedly(Return(syncer::UserSelectableTypes()));
diff --git a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc index 9524961..70e2ff3 100644 --- a/chrome/browser/ui/sync/one_click_signin_sync_starter.cc +++ b/chrome/browser/ui/sync/one_click_signin_sync_starter.cc
@@ -419,7 +419,7 @@ base::UserMetricsAction("Signin_Signin_WithDefaultSyncSettings")); ProfileSyncService* profile_sync_service = GetProfileSyncService(); if (profile_sync_service) - profile_sync_service->SetSyncSetupCompleted(); + profile_sync_service->SetFirstSetupComplete(); FinishProfileSyncServiceSetup(); } @@ -473,7 +473,7 @@ // Just kick off the sync machine, no need to configure it first. ProfileSyncService* profile_sync_service = GetProfileSyncService(); if (profile_sync_service) - profile_sync_service->SetSyncSetupCompleted(); + profile_sync_service->SetFirstSetupComplete(); FinishProfileSyncServiceSetup(); if (confirmation_required_ == CONFIRM_AFTER_SIGNIN) { base::string16 message;
diff --git a/chrome/browser/ui/views/passwords/OWNERS b/chrome/browser/ui/views/passwords/OWNERS index 75a4ab7c..2c5da5ec3 100644 --- a/chrome/browser/ui/views/passwords/OWNERS +++ b/chrome/browser/ui/views/passwords/OWNERS
@@ -1,4 +1,2 @@ -markusheintz@chromium.org -mkwst@chromium.org vabr@chromium.org vasilii@chromium.org
diff --git a/chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.cc b/chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.cc index 7dcad46..e0bca8b 100644 --- a/chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.cc +++ b/chrome/browser/ui/webui/ntp/new_tab_page_sync_handler.cc
@@ -101,7 +101,7 @@ } // Don't show sync status if setup is not complete. - if (!sync_service_->HasSyncSetupCompleted()) { + if (!sync_service_->IsFirstSetupComplete()) { return; } @@ -133,7 +133,7 @@ chrome::ShowBrowserSignin(browser, signin_metrics::AccessPoint::ACCESS_POINT_NTP_LINK); - if (sync_service_->HasSyncSetupCompleted()) { + if (sync_service_->IsFirstSetupComplete()) { base::string16 user = base::UTF8ToUTF16( SigninManagerFactory::GetForProfile(Profile::FromWebUI(web_ui())) ->GetAuthenticatedAccountInfo()
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index d043e41..8337d625 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -1446,7 +1446,7 @@ sync_status->SetBoolean("signinAllowed", signin->IsSigninAllowed()); sync_status->SetBoolean("syncSystemEnabled", (service != NULL)); sync_status->SetBoolean("setupCompleted", - service && service->HasSyncSetupCompleted()); + service && service->IsFirstSetupComplete()); sync_status->SetBoolean("setupInProgress", service && !service->IsManaged() && service->IsFirstSetupInProgress());
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler.cc b/chrome/browser/ui/webui/options/sync_setup_handler.cc index 639f068..653c6f5 100644 --- a/chrome/browser/ui/webui/options/sync_setup_handler.cc +++ b/chrome/browser/ui/webui/options/sync_setup_handler.cc
@@ -297,7 +297,7 @@ ProfileSyncService* service = GetSyncService(); DCHECK(service); - if (!service->HasSyncSetupCompleted()) { + if (!service->IsFirstSetupComplete()) { // This is the first time configuring sync, so log it. base::FilePath profile_file_path = GetProfile()->GetPath(); ProfileMetrics::LogProfileSyncSignIn(profile_file_path); @@ -305,7 +305,7 @@ // We're done configuring, so notify ProfileSyncService that it is OK to // start syncing. service->SetSetupInProgress(false); - service->SetSyncSetupCompleted(); + service->SetFirstSetupComplete(); } } @@ -698,8 +698,9 @@ if (IsActiveLogin()) { // Don't log a cancel event if the sync setup dialog is being // automatically closed due to an auth error. - if (!sync_service || (!sync_service->HasSyncSetupCompleted() && - sync_service->GetAuthError().state() == GoogleServiceAuthError::NONE)) { + if (!sync_service || (!sync_service->IsFirstSetupComplete() && + sync_service->GetAuthError().state() == + GoogleServiceAuthError::NONE)) { if (configuring_sync_) { ProfileSyncService::SyncEvent( ProfileSyncService::CANCEL_DURING_CONFIGURE);
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc index 7fcc635..c2e53de 100644 --- a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc +++ b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
@@ -308,8 +308,7 @@ #if !defined(OS_CHROMEOS) TEST_F(SyncSetupHandlerFirstSigninTest, DisplayBasicLogin) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Ensure that the user is not signed in before calling |HandleStartSignin()|. SigninManager* manager = static_cast<SigninManager*>(mock_signin_); manager->SignOut(signin_metrics::SIGNOUT_TEST); @@ -330,8 +329,7 @@ TEST_F(SyncSetupHandlerTest, ShowSyncSetupWhenNotSignedIn) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); handler_->HandleShowSetupUI(NULL); // We expect a call to SyncSetupOverlay.showSyncSetupPage. @@ -363,8 +361,7 @@ // it is displaying the spinner to the user. TEST_F(SyncSetupHandlerTest, DisplayConfigureWithBackendDisabledAndCancel) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); EXPECT_CALL(*mock_pss_, IsBackendInitialized()).WillRepeatedly(Return(false)); @@ -387,8 +384,7 @@ TEST_F(SyncSetupHandlerTest, DisplayConfigureWithBackendDisabledAndSyncStartupCompleted) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); // Sync backend is stopped initially, and will start up. EXPECT_CALL(*mock_pss_, IsBackendInitialized()).WillRepeatedly(Return(false)); @@ -436,8 +432,7 @@ TEST_F(SyncSetupHandlerTest, DisplayConfigureWithBackendDisabledAndCancelAfterSigninSuccess) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); EXPECT_CALL(*mock_pss_, IsBackendInitialized()) .WillOnce(Return(false)) @@ -460,8 +455,7 @@ TEST_F(SyncSetupHandlerTest, DisplayConfigureWithBackendDisabledAndSigninFailed) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); EXPECT_CALL(*mock_pss_, IsBackendInitialized()).WillRepeatedly(Return(false)); @@ -494,8 +488,7 @@ EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); EXPECT_CALL(*mock_pss_, HasUnrecoverableError()) .WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Open the web UI. handler_->OpenSyncSetup(nullptr); @@ -505,8 +498,7 @@ // TODO(kochi): We need equivalent tests for ChromeOS. TEST_F(SyncSetupHandlerNonCrosTest, UnrecoverableErrorInitializingSync) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Open the web UI. handler_->OpenSyncSetup(nullptr); @@ -515,8 +507,7 @@ TEST_F(SyncSetupHandlerNonCrosTest, GaiaErrorInitializingSync) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Open the web UI. handler_->OpenSyncSetup(nullptr);
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc index ffb02c8..81f47a9 100644 --- a/chrome/browser/ui/webui/settings/people_handler.cc +++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -243,7 +243,7 @@ ProfileSyncService* service = GetSyncService(); DCHECK(service); - if (!service->HasSyncSetupCompleted()) { + if (!service->IsFirstSetupComplete()) { // This is the first time configuring sync, so log it. base::FilePath profile_file_path = profile_->GetPath(); ProfileMetrics::LogProfileSyncSignIn(profile_file_path); @@ -251,7 +251,7 @@ // We're done configuring, so notify ProfileSyncService that it is OK to // start syncing. service->SetSetupInProgress(false); - service->SetSyncSetupCompleted(); + service->SetFirstSetupComplete(); } } @@ -658,7 +658,7 @@ if (IsActiveLogin()) { // Don't log a cancel event if the sync setup dialog is being // automatically closed due to an auth error. - if (!sync_service || (!sync_service->HasSyncSetupCompleted() && + if (!sync_service || (!sync_service->IsFirstSetupComplete() && sync_service->GetAuthError().state() == GoogleServiceAuthError::NONE)) { if (configuring_sync_) { @@ -825,7 +825,7 @@ sync_status->SetBoolean("signinAllowed", signin->IsSigninAllowed()); sync_status->SetBoolean("syncSystemEnabled", (service != nullptr)); sync_status->SetBoolean("setupCompleted", - service && service->HasSyncSetupCompleted()); + service && service->IsFirstSetupComplete()); sync_status->SetBoolean( "setupInProgress", service && !service->IsManaged() && service->IsFirstSetupInProgress());
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc index 48db8c87..ab5cff3 100644 --- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc +++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -313,8 +313,7 @@ #if !defined(OS_CHROMEOS) TEST_F(PeopleHandlerFirstSigninTest, DisplayBasicLogin) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Ensure that the user is not signed in before calling |HandleStartSignin()|. SigninManager* manager = static_cast<SigninManager*>(mock_signin_); manager->SignOut(signin_metrics::SIGNOUT_TEST); @@ -335,8 +334,7 @@ TEST_F(PeopleHandlerTest, ShowSyncSetupWhenNotSignedIn) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); handler_->HandleShowSetupUI(NULL); // We expect a call to settings.SyncPrivateApi.showSyncSetupPage. @@ -368,8 +366,7 @@ // it is displaying the spinner to the user. TEST_F(PeopleHandlerTest, DisplayConfigureWithBackendDisabledAndCancel) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); EXPECT_CALL(*mock_pss_, IsBackendInitialized()).WillRepeatedly(Return(false)); @@ -392,8 +389,7 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithBackendDisabledAndSyncStartupCompleted) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); // Sync backend is stopped initially, and will start up. EXPECT_CALL(*mock_pss_, IsBackendInitialized()).WillRepeatedly(Return(false)); @@ -441,8 +437,7 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithBackendDisabledAndCancelAfterSigninSuccess) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); EXPECT_CALL(*mock_pss_, IsBackendInitialized()) .WillOnce(Return(false)) @@ -465,8 +460,7 @@ TEST_F(PeopleHandlerTest, DisplayConfigureWithBackendDisabledAndSigninFailed) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(true)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); error_ = GoogleServiceAuthError::AuthErrorNone(); EXPECT_CALL(*mock_pss_, IsBackendInitialized()).WillRepeatedly(Return(false)); @@ -499,8 +493,7 @@ EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); EXPECT_CALL(*mock_pss_, HasUnrecoverableError()) .WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Open the web UI. handler_->OpenSyncSetup(nullptr); @@ -510,8 +503,7 @@ // TODO(kochi): We need equivalent tests for ChromeOS. TEST_F(PeopleHandlerNonCrosTest, UnrecoverableErrorInitializingSync) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Open the web UI. handler_->OpenSyncSetup(nullptr); @@ -520,8 +512,7 @@ TEST_F(PeopleHandlerNonCrosTest, GaiaErrorInitializingSync) { EXPECT_CALL(*mock_pss_, CanSyncStart()).WillRepeatedly(Return(false)); - EXPECT_CALL(*mock_pss_, HasSyncSetupCompleted()) - .WillRepeatedly(Return(false)); + EXPECT_CALL(*mock_pss_, IsFirstSetupComplete()).WillRepeatedly(Return(false)); // Open the web UI. handler_->OpenSyncSetup(nullptr);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc index ce278b2..608e66d 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -330,9 +330,8 @@ if (access_point == signin_metrics::AccessPoint::ACCESS_POINT_SETTINGS || choose_what_to_sync_) { bool show_settings_without_configure = - error_controller->HasError() && - sync_service && - sync_service->HasSyncSetupCompleted(); + error_controller->HasError() && sync_service && + sync_service->IsFirstSetupComplete(); start_mode = show_settings_without_configure ? OneClickSigninSyncStarter::SHOW_SETTINGS_WITHOUT_CONFIGURE : OneClickSigninSyncStarter::CONFIGURE_SYNC_FIRST;
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index aec8cb2..ca0677c 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi
@@ -738,6 +738,8 @@ 'browser/android/download/chrome_download_delegate.h', 'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.cc', 'browser/android/download/chrome_download_manager_overwrite_infobar_delegate.h', + 'browser/android/download/download_manager_service.cc', + 'browser/android/download/download_manager_service.h', 'browser/android/download/download_overwrite_infobar_delegate.cc', 'browser/android/download/download_overwrite_infobar_delegate.h', 'browser/android/download/mock_download_controller_android.cc', @@ -1837,6 +1839,7 @@ 'android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerTabUtils.java', 'android/java/src/org/chromium/chrome/browser/dom_distiller/DomDistillerUIUtils.java', 'android/java/src/org/chromium/chrome/browser/download/ChromeDownloadDelegate.java', + 'android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java', 'android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java', 'android/java/src/org/chromium/chrome/browser/favicon/LargeIconBridge.java', 'android/java/src/org/chromium/chrome/browser/feedback/ConnectivityChecker.java', @@ -3821,6 +3824,7 @@ '../chrome_elf/chrome_elf.gyp:dll_hash', '../components/components.gyp:browser_watcher', '../components/components.gyp:browser_watcher_client', + '../components/components.gyp:startup_metric_utils_common', '../google_update/google_update.gyp:google_update', '../third_party/iaccessible2/iaccessible2.gyp:iaccessible2', '../third_party/isimpledom/isimpledom.gyp:isimpledom',
diff --git a/chrome/chrome_dll.gypi b/chrome/chrome_dll.gypi index a0aa2c1..0f781cd 100644 --- a/chrome/chrome_dll.gypi +++ b/chrome/chrome_dll.gypi
@@ -372,6 +372,22 @@ }], ['OS=="win"', { 'conditions': [ + ['chrome_pgo_phase!=0', { + # Disable Warning 4702 ("Unreachable code") for the WPO/PGO + # builds. Probably anything that this would catch that + # wouldn't be caught in a normal build isn't going to + # actually be a bug, so the incremental value of C4702 for + # PGO builds is likely very small. + 'msvs_disabled_warnings': [ + 4702 + ], + 'msvs_settings': { + 'VCCLCompilerTool': { + # This implies link time code generation. + 'WholeProgramOptimization': 'true', + }, + }, + }], ['chrome_pgo_phase==1', { 'msvs_settings': { 'VCLinkerTool': {
diff --git a/chrome/chrome_exe.gypi b/chrome/chrome_exe.gypi index fda73bc..21cb8ea 100644 --- a/chrome/chrome_exe.gypi +++ b/chrome/chrome_exe.gypi
@@ -425,6 +425,7 @@ '../components/components.gyp:crash_component', '../components/components.gyp:crash_core_common', '../components/components.gyp:flags_ui_switches', + '../components/components.gyp:startup_metric_utils_common', '../sandbox/sandbox.gyp:sandbox', '../third_party/kasko/kasko.gyp:kasko_features', '../ui/gfx/gfx.gyp:gfx',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 35df53ed..e78ed7e 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -1591,6 +1591,8 @@ 'sources': [ 'browser/password_manager/password_manager_test_base.cc', 'browser/password_manager/password_manager_test_base.h', + 'browser/signin/token_revoker_test_utils.cc', + 'browser/signin/token_revoker_test_utils.h', 'browser/ui/webui/signin/login_ui_test_utils.cc', 'browser/ui/webui/signin/login_ui_test_utils.h', 'test/base/in_process_browser_test.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index da034204..3cfed39 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -18,6 +18,7 @@ 'browser/android/data_usage/data_use_ui_tab_model_unittest.cc', 'browser/android/data_usage/external_data_use_observer_unittest.cc', 'browser/android/data_usage/tab_data_use_entry_unittest.cc', + 'browser/android/download/download_manager_service_unittest.cc', 'browser/android/history_report/delta_file_backend_leveldb_unittest.cc', 'browser/android/history_report/delta_file_commons_unittest.cc', 'browser/android/history_report/usage_reports_buffer_backend_unittest.cc',
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json index d24d6ec..671d571 100644 --- a/chrome/common/extensions/api/_permission_features.json +++ b/chrome/common/extensions/api/_permission_features.json
@@ -352,7 +352,9 @@ "657FEC7E77355CA205B0E226586621F86B33F611", // http://crbug.com/246857 "5894126C625EF31852F215ED301A5FF1F9B7D026", // http://crbug.com/246857 "8DAE23A10703C926B21862B2F318FB4E110B17BD", // http://crbug.com/487455 - "34412790FC81BC9B563CBE599ED10ABF26B209F7" // http://crbug.com/509149 + "34412790FC81BC9B563CBE599ED10ABF26B209F7", // http://crbug.com/509149 + "7F782E724FF51789B54DA82C7363DAB5043C1677", // http://crbug.com/570127 + "2C18988BCDC297196D5D6893005175DA1BC1E893" // http://crbug.com/570127 ] }, "experienceSamplingPrivate": {
diff --git a/chrome/common/localized_error.cc b/chrome/common/localized_error.cc index c78fbf75..8ff1643 100644 --- a/chrome/common/localized_error.cc +++ b/chrome/common/localized_error.cc
@@ -17,8 +17,6 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "build/build_config.h" -#include "chrome/grit/chromium_strings.h" -#include "chrome/grit/google_chrome_strings.h" #include "components/error_page/common/error_page_params.h" #include "components/error_page/common/error_page_switches.h" #include "components/error_page/common/net_error_info.h" @@ -625,8 +623,6 @@ summary->SetString("failedUrl", failed_url_string); summary->SetString("hostName", host_name); - summary->SetString("productName", - l10n_util::GetStringUTF16(IDS_PRODUCT_NAME)); error_strings->SetString( "details", l10n_util::GetStringUTF16(IDS_ERRORPAGE_NET_BUTTON_DETAILS));
diff --git a/chrome/common/safe_browsing/download_protection_util.cc b/chrome/common/safe_browsing/download_protection_util.cc index 05b769a..8baa601f 100644 --- a/chrome/common/safe_browsing/download_protection_util.cc +++ b/chrome/common/safe_browsing/download_protection_util.cc
@@ -266,6 +266,7 @@ EXTENSION_MSG, EXTENSION_EML, EXTENSION_RTF, + EXTENSION_VHDX, // New values go above this one. EXTENSION_MAX @@ -497,6 +498,7 @@ {FILE_PATH_LITERAL(".vbs"), EXTENSION_VBS, true, false}, {FILE_PATH_LITERAL(".vbscript"), EXTENSION_VBSCRIPT, false, false}, // UMA. {FILE_PATH_LITERAL(".vhd"), EXTENSION_VHD, true, true}, + {FILE_PATH_LITERAL(".vhdx"), EXTENSION_VHDX, true, true}, {FILE_PATH_LITERAL(".vmdk"), EXTENSION_VMDK, true, true}, {FILE_PATH_LITERAL(".vsd"), EXTENSION_VSD, true, false}, {FILE_PATH_LITERAL(".vsmacros"), EXTENSION_VSMACROS, true, false},
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java index 2bbcb56..547b4e0 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java
@@ -84,9 +84,10 @@ File[] files = new File(appDir).listFiles(); if (files == null) return true; for (File file : files) { - if (!(file.getAbsolutePath().endsWith("/lib") - || file.getAbsolutePath().endsWith("/etp_native") // Work Chrome - || file.getAbsolutePath().endsWith("/sdk_dex")) // Work Chrome + if (!(file.getName().equals("lib") + || file.getName().equals("etp_native") // Work Chrome + || file.getName().equals("sdk_dex") // Work Chrome + || file.getName().equals("incremental-install-files")) && !removeFile(file)) { return false; }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM index 186115a..22cc9488 100644 --- a/chromeos/CHROMEOS_LKGM +++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@ -7830.0.0 \ No newline at end of file +7842.0.0 \ No newline at end of file
diff --git a/components/autofill/core/browser/autofill_experiments.cc b/components/autofill/core/browser/autofill_experiments.cc index 9f36ca62..f070742 100644 --- a/components/autofill/core/browser/autofill_experiments.cc +++ b/components/autofill/core/browser/autofill_experiments.cc
@@ -67,7 +67,7 @@ // Users who have enabled a passphrase have chosen to not make their sync // information accessible to Google. Since upload makes credit card data // available to other Google systems, disable it for passphrase users. - if (sync_service->HasSyncSetupCompleted() && + if (sync_service->IsFirstSetupComplete() && sync_service->IsUsingSecondaryPassphrase()) { return false; }
diff --git a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc b/components/autofill/core/browser/autofill_wallet_data_type_controller.cc index 2eb1127..811d967 100644 --- a/components/autofill/core/browser/autofill_wallet_data_type_controller.cc +++ b/components/autofill/core/browser/autofill_wallet_data_type_controller.cc
@@ -93,11 +93,11 @@ // syncing local data between clients, so this extra step is required. sync_driver::SyncService* service = sync_client_->GetSyncService(); - // HasSyncSetupCompleted indicates if sync is currently enabled at all. The + // IsFirstSetupComplete indicates if sync is currently enabled at all. The // preferred data type indicates if wallet sync data/metadata is enabled, and // currently_enabled_ indicates if the other prefs are enabled. All of these // have to be enabled to sync wallet data/metadata. - if (!service->HasSyncSetupCompleted() || + if (!service->IsFirstSetupComplete() || !service->GetPreferredDataTypes().Has(type()) || !currently_enabled_) { autofill::PersonalDataManager* pdm = sync_client_->GetPersonalDataManager(); if (pdm)
diff --git a/components/browser_sync/browser/profile_sync_service.cc b/components/browser_sync/browser/profile_sync_service.cc index ecbb2d2..0a5237e8 100644 --- a/components/browser_sync/browser/profile_sync_service.cc +++ b/components/browser_sync/browser/profile_sync_service.cc
@@ -309,12 +309,12 @@ // plumbed into PSS until after this function. See http://crbug.com/568771. sync_state = NOT_ALLOWED_BY_PLATFORM; } else if (!IsSyncRequested()) { - if (HasSyncSetupCompleted()) { + if (IsFirstSetupComplete()) { sync_state = NOT_REQUESTED; } else { sync_state = NOT_REQUESTED_NOT_SETUP; } - } else if (!HasSyncSetupCompleted()) { + } else if (!IsFirstSetupComplete()) { sync_state = NEEDS_CONFIRMATION; } UMA_HISTOGRAM_ENUMERATION("Sync.InitialState", sync_state, @@ -329,7 +329,7 @@ RegisterAuthNotifications(); - if (!HasSyncSetupCompleted() || !IsSignedIn()) { + if (!IsFirstSetupComplete() || !IsSignedIn()) { // Clean up in case of previous crash / setup abort / signout. StopImpl(CLEAR_DATA); } @@ -379,7 +379,7 @@ void ProfileSyncService::TrySyncDatatypePrefRecovery() { DCHECK(!IsBackendInitialized()); - if (!HasSyncSetupCompleted()) + if (!IsFirstSetupComplete()) return; // There was a bug where OnUserChoseDatatypes was not properly called on @@ -511,7 +511,7 @@ bool ProfileSyncService::ShouldDeleteSyncFolder() { switch (backend_mode_) { case SYNC: - return !HasSyncSetupCompleted(); + return !IsFirstSetupComplete(); case BACKUP: return true; case ROLLBACK: @@ -933,12 +933,12 @@ } } -bool ProfileSyncService::HasSyncSetupCompleted() const { - return sync_prefs_.HasSyncSetupCompleted(); +bool ProfileSyncService::IsFirstSetupComplete() const { + return sync_prefs_.IsFirstSetupComplete(); } -void ProfileSyncService::SetSyncSetupCompleted() { - sync_prefs_.SetSyncSetupCompleted(); +void ProfileSyncService::SetFirstSetupComplete() { + sync_prefs_.SetFirstSetupComplete(); } void ProfileSyncService::UpdateLastSyncedTime() { @@ -1020,7 +1020,7 @@ if (backend_mode_ != SYNC) return; - is_first_time_sync_configure_ = !HasSyncSetupCompleted(); + is_first_time_sync_configure_ = !IsFirstSetupComplete(); if (is_first_time_sync_configure_) { UMA_HISTOGRAM_BOOLEAN("Sync.BackendInitializeFirstTimeSuccess", success); @@ -1071,13 +1071,13 @@ // Backend is initialized but we're not in sync setup, so this must be an // autostart - mark our sync setup as completed and we'll start syncing // below. - SetSyncSetupCompleted(); + SetFirstSetupComplete(); } - // Check HasSyncSetupCompleted() before NotifyObservers() to avoid spurious + // Check IsFirstSetupComplete() before NotifyObservers() to avoid spurious // data type configuration because observer may flag setup as complete and // trigger data type configuration. - if (HasSyncSetupCompleted()) { + if (IsFirstSetupComplete()) { ConfigureDataTypeManager(); } else { DCHECK(IsFirstSetupInProgress()); @@ -1591,9 +1591,9 @@ return BACKUP_USER_DATA; } else if (backend_mode_ == ROLLBACK) { return ROLLBACK_USER_DATA; - } else if (backend_.get() && !HasSyncSetupCompleted()) { + } else if (backend_.get() && !IsFirstSetupComplete()) { return SETUP_INCOMPLETE; - } else if (backend_ && HasSyncSetupCompleted() && data_type_manager_ && + } else if (backend_ && IsFirstSetupComplete() && data_type_manager_ && data_type_manager_->state() == DataTypeManager::STOPPED) { return DATATYPES_NOT_INITIALIZED; } else if (IsSyncActive()) { @@ -1659,7 +1659,7 @@ } bool ProfileSyncService::IsFirstSetupInProgress() const { - return !HasSyncSetupCompleted() && startup_controller_->IsSetupInProgress(); + return !IsFirstSetupComplete() && startup_controller_->IsSetupInProgress(); } void ProfileSyncService::SetSetupInProgress(bool setup_in_progress) { @@ -1746,7 +1746,7 @@ void ProfileSyncService::UpdateSelectedTypesHistogram( bool sync_everything, const syncer::ModelTypeSet chosen_types) const { - if (!HasSyncSetupCompleted() || + if (!IsFirstSetupComplete() || sync_everything != sync_prefs_.HasKeepEverythingSynced()) { UMA_HISTOGRAM_BOOLEAN("Sync.SyncEverything", sync_everything); } @@ -1783,7 +1783,7 @@ ++i, it.Inc()) { const syncer::ModelType type = it.Get(); if (chosen_types.Has(type) && - (!HasSyncSetupCompleted() || !current_types.Has(type))) { + (!IsFirstSetupComplete() || !current_types.Has(type))) { // Selected type has changed - log it. UMA_HISTOGRAM_ENUMERATION( "Sync.CustomSync", @@ -1945,7 +1945,7 @@ reason = syncer::CONFIGURE_REASON_BACKUP_ROLLBACK; } else { types = GetPreferredDataTypes(); - if (!HasSyncSetupCompleted()) { + if (!IsFirstSetupComplete()) { reason = syncer::CONFIGURE_REASON_NEW_CLIENT; } else if (restart) { // Datatype downloads on restart are generally due to newly supported
diff --git a/components/browser_sync/browser/profile_sync_service.h b/components/browser_sync/browser/profile_sync_service.h index 3ab8909..ada1731 100644 --- a/components/browser_sync/browser/profile_sync_service.h +++ b/components/browser_sync/browser/profile_sync_service.h
@@ -159,18 +159,18 @@ // types until the user has finished setting up sync. There are two APIs // that control the initial sync download: // -// * SetSyncSetupCompleted() +// * SetFirstSetupComplete() // * SetSetupInProgress() // -// SetSyncSetupCompleted() should be called once the user has finished setting +// SetFirstSetupComplete() should be called once the user has finished setting // up sync at least once on their account. SetSetupInProgress(true) should be // called while the user is actively configuring their account, and then // SetSetupInProgress(false) should be called when configuration is complete. -// When SetSyncSetupCompleted() == false, but SetSetupInProgress(true) has +// When SetFirstSetupComplete() == false, but SetSetupInProgress(true) has // been called, then the sync engine knows not to download any user data. // // When initial sync is complete, the UI code should call -// SetSyncSetupCompleted() followed by SetSetupInProgress(false) - this will +// SetFirstSetupComplete() followed by SetSetupInProgress(false) - this will // tell the sync engine that setup is completed and it can begin downloading // data from the sync server. // @@ -267,7 +267,7 @@ void Initialize(); // sync_driver::SyncService implementation - bool HasSyncSetupCompleted() const override; + bool IsFirstSetupComplete() const override; bool IsSyncAllowed() const override; bool IsSyncActive() const override; void TriggerRefresh(const syncer::ModelTypeSet& types) override; @@ -280,7 +280,7 @@ syncer::ModelTypeSet GetPreferredDataTypes() const override; void OnUserChoseDatatypes(bool sync_everything, syncer::ModelTypeSet chosen_types) override; - void SetSyncSetupCompleted() override; + void SetFirstSetupComplete() override; bool IsFirstSetupInProgress() const override; void SetSetupInProgress(bool setup_in_progress) override; bool IsSetupInProgress() const override; @@ -428,7 +428,7 @@ // Returns true if sync is requested to be running by the user. // Note that this does not mean that sync WILL be running; e.g. if // IsSyncAllowed() is false then sync won't start, and if the user - // doesn't confirm their settings (HasSyncSetupCompleted), sync will + // doesn't confirm their settings (IsFirstSetupComplete), sync will // never become active. Use IsSyncActive to see if sync is running. virtual bool IsSyncRequested() const; @@ -858,7 +858,7 @@ base::SequencedWorkerPool* blocking_pool_; // Indicates if this is the first time sync is being configured. This value - // is equal to !HasSyncSetupCompleted() at the time of OnBackendInitialized(). + // is equal to !IsFirstSetupComplete() at the time of OnBackendInitialized(). bool is_first_time_sync_configure_; // List of available data type controllers.
diff --git a/components/browser_sync/browser/profile_sync_service_mock.h b/components/browser_sync/browser/profile_sync_service_mock.h index b05fec4..41df3eae2 100644 --- a/components/browser_sync/browser/profile_sync_service_mock.h +++ b/components/browser_sync/browser/profile_sync_service_mock.h
@@ -51,7 +51,7 @@ MOCK_METHOD1(AddObserver, void(sync_driver::SyncServiceObserver*)); MOCK_METHOD1(RemoveObserver, void(sync_driver::SyncServiceObserver*)); MOCK_METHOD0(GetJsController, base::WeakPtr<syncer::JsController>()); - MOCK_CONST_METHOD0(HasSyncSetupCompleted, bool()); + MOCK_CONST_METHOD0(IsFirstSetupComplete, bool()); MOCK_CONST_METHOD0(IsEncryptEverythingAllowed, bool()); MOCK_CONST_METHOD0(IsEncryptEverythingEnabled, bool());
diff --git a/components/browser_sync/browser/profile_sync_service_unittest.cc b/components/browser_sync/browser/profile_sync_service_unittest.cc index e13b9ecf..81e746c9 100644 --- a/components/browser_sync/browser/profile_sync_service_unittest.cc +++ b/components/browser_sync/browser/profile_sync_service_unittest.cc
@@ -356,7 +356,7 @@ sync_driver::SyncPrefs sync_prefs( service_->GetSyncClient()->GetPrefService()); sync_prefs.SetFirstSyncTime(base::Time::Now()); - sync_prefs.SetSyncSetupCompleted(); + sync_prefs.SetFirstSetupComplete(); sync_prefs.SetKeepEverythingSynced(true); service_->Initialize(); } @@ -782,7 +782,7 @@ TEST_F(ProfileSyncServiceTest, Rollback) { CreateService(browser_sync::MANUAL_START); - service()->SetSyncSetupCompleted(); + service()->SetFirstSetupComplete(); ExpectDataTypeManagerCreation(2, GetDefaultConfigureCalledCallback()); std::vector<bool> delete_dir_param; ExpectSyncBackendHostCreationCollectDeleteDir(2, &delete_dir_param);
diff --git a/components/history/core/browser/top_sites_impl.cc b/components/history/core/browser/top_sites_impl.cc index 28d521d..09458bf18 100644 --- a/components/history/core/browser/top_sites_impl.cc +++ b/components/history/core/browser/top_sites_impl.cc
@@ -85,7 +85,7 @@ // On mobile, having the max at 60 minutes results in the topsites database // being not updated often enough since the app isn't usually running for long // stretches of time. -const int64_t kMaxUpdateIntervalMinutes = 1; +const int64_t kMaxUpdateIntervalMinutes = 5; #else const int64_t kMaxUpdateIntervalMinutes = 60; #endif // defined(OS_IOS) || defined(OS_ANDROID)
diff --git a/components/history/core/browser/top_sites_impl_unittest.cc b/components/history/core/browser/top_sites_impl_unittest.cc index 042fd21b..2efb4afd 100644 --- a/components/history/core/browser/top_sites_impl_unittest.cc +++ b/components/history/core/browser/top_sites_impl_unittest.cc
@@ -972,8 +972,8 @@ TEST_F(TopSitesImplTest, GetUpdateDelay) { #if defined(OS_IOS) || defined(OS_ANDROID) const int64_t kExpectedUpdateDelayInSecondEmpty = 30; - const int64_t kExpectedUpdateDelayInMinute0Changed = 1; - const int64_t kExpectedUpdateDelayInMinute3Changed = 1; + const int64_t kExpectedUpdateDelayInMinute0Changed = 5; + const int64_t kExpectedUpdateDelayInMinute3Changed = 5; const int64_t kExpectedUpdateDelayInMinute20Changed = 1; #else const int64_t kExpectedUpdateDelayInSecondEmpty = 30;
diff --git a/components/mus/surfaces/direct_output_surface.cc b/components/mus/surfaces/direct_output_surface.cc index 88f1f662..8700900 100644 --- a/components/mus/surfaces/direct_output_surface.cc +++ b/components/mus/surfaces/direct_output_surface.cc
@@ -49,7 +49,6 @@ gpu::SyncToken sync_token; gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); - context_provider_->ContextGL()->InsertSyncPointCHROMIUM(); context_provider_->ContextSupport()->SignalSyncToken( sync_token, base::Bind(&OutputSurface::OnSwapBuffersComplete,
diff --git a/components/password_manager/core/browser/password_bubble_experiment_unittest.cc b/components/password_manager/core/browser/password_bubble_experiment_unittest.cc index cdac12c0..54c23b6 100644 --- a/components/password_manager/core/browser/password_bubble_experiment_unittest.cc +++ b/components/password_manager/core/browser/password_bubble_experiment_unittest.cc
@@ -72,7 +72,7 @@ // FakeSyncService overrides. bool IsSyncAllowed() const override { return true; } - bool HasSyncSetupCompleted() const override { return true; } + bool IsFirstSetupComplete() const override { return true; } bool IsSyncActive() const override { return true; }
diff --git a/components/password_manager/core/browser/password_manager_util.cc b/components/password_manager/core/browser/password_manager_util.cc index bd7ca1c..c4ccce1 100644 --- a/components/password_manager/core/browser/password_manager_util.cc +++ b/components/password_manager/core/browser/password_manager_util.cc
@@ -14,7 +14,7 @@ password_manager::PasswordSyncState GetPasswordSyncState( const sync_driver::SyncService* sync_service) { - if (sync_service && sync_service->HasSyncSetupCompleted() && + if (sync_service && sync_service->IsFirstSetupComplete() && sync_service->IsSyncActive() && sync_service->GetActiveDataTypes().Has(syncer::PASSWORDS)) { return sync_service->IsUsingSecondaryPassphrase()
diff --git a/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc b/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc index 0823b74d..7dc8671a 100644 --- a/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc +++ b/components/password_manager/sync/browser/password_manager_setting_migrator_service_unittest.cc
@@ -124,7 +124,7 @@ class SyncServiceMock : public sync_driver::FakeSyncService { public: - bool HasSyncSetupCompleted() const override { return true; } + bool IsFirstSetupComplete() const override { return true; } bool CanSyncStart() const override { return can_sync_start_; }
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.cc b/components/scheduler/renderer/renderer_scheduler_impl.cc index 33e7b8d..9d8d7bb 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl.cc
@@ -42,7 +42,6 @@ TRACE_DISABLED_BY_DEFAULT("renderer.scheduler"), "RendererSchedulerIdlePeriod", base::TimeDelta()), - throttling_helper_(this, "renderer.scheduler"), render_widget_scheduler_signals_(this), control_task_runner_(helper_.ControlTaskRunner()), compositor_task_runner_( @@ -56,6 +55,7 @@ helper_.scheduler_tqm_delegate().get()), policy_may_need_update_(&any_thread_lock_), weak_factory_(this) { + throttling_helper_.reset(new ThrottlingHelper(this, "renderer.scheduler")); update_policy_closure_ = base::Bind(&RendererSchedulerImpl::UpdatePolicy, weak_factory_.GetWeakPtr()); end_renderer_hidden_idle_period_closure_.Reset(base::Bind( @@ -95,12 +95,6 @@ DCHECK(MainThreadOnly().was_shutdown); } -RendererSchedulerImpl::Policy::Policy() - : compositor_queue_priority(TaskQueue::NORMAL_PRIORITY), - loading_queue_priority(TaskQueue::NORMAL_PRIORITY), - timer_queue_priority(TaskQueue::NORMAL_PRIORITY), - default_queue_priority(TaskQueue::NORMAL_PRIORITY) {} - RendererSchedulerImpl::MainThreadOnly::MainThreadOnly( const scoped_refptr<TaskQueue>& compositor_task_runner, base::TickClock* time_source) @@ -147,6 +141,7 @@ RendererSchedulerImpl::CompositorThreadOnly::~CompositorThreadOnly() {} void RendererSchedulerImpl::Shutdown() { + throttling_helper_.reset(); helper_.Shutdown(); MainThreadOnly().was_shutdown = true; } @@ -194,7 +189,7 @@ TaskQueue::Spec(name).SetShouldMonitorQuiescence(true))); loading_task_runners_.insert(loading_task_queue); loading_task_queue->SetQueuePriority( - MainThreadOnly().current_policy.loading_queue_priority); + MainThreadOnly().current_policy.loading_queue_policy.priority); loading_task_queue->AddTaskObserver( &MainThreadOnly().loading_task_cost_estimator); return loading_task_queue; @@ -207,7 +202,7 @@ TaskQueue::Spec(name).SetShouldMonitorQuiescence(true))); timer_task_runners_.insert(timer_task_queue); timer_task_queue->SetQueuePriority( - MainThreadOnly().current_policy.timer_queue_priority); + MainThreadOnly().current_policy.timer_queue_policy.priority); timer_task_queue->AddTaskObserver( &MainThreadOnly().timer_task_cost_estimator); return timer_task_queue; @@ -657,27 +652,30 @@ } Policy new_policy; - bool block_expensive_loading_tasks = false; - bool block_expensive_timer_tasks = false; + enum class ExpensiveTaskPolicy { RUN, BLOCK, THROTTLE }; + ExpensiveTaskPolicy expensive_task_policy = ExpensiveTaskPolicy::RUN; switch (use_case) { case UseCase::COMPOSITOR_GESTURE: if (touchstart_expected_soon) { - block_expensive_loading_tasks = true; - block_expensive_timer_tasks = true; - new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; } else { // What we really want to do is priorize loading tasks, but that doesn't // seem to be safe. Instead we do that by proxy by deprioritizing // compositor tasks. This should be safe since we've already gone to the // pain of fixing ordering issues with them. - new_policy.compositor_queue_priority = TaskQueue::BEST_EFFORT_PRIORITY; + new_policy.compositor_queue_policy.priority = + TaskQueue::BEST_EFFORT_PRIORITY; } break; case UseCase::SYNCHRONIZED_GESTURE: - new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; - block_expensive_loading_tasks = true; - block_expensive_timer_tasks = true; + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + if (touchstart_expected_soon) { + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; + } else { + expensive_task_policy = ExpensiveTaskPolicy::THROTTLE; + } break; case UseCase::MAIN_THREAD_GESTURE: @@ -685,71 +683,68 @@ // things we should be prioritizing, so we don't attempt to block // expensive tasks because we don't know whether they were integral to the // page's functionality or not. - new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; break; case UseCase::TOUCHSTART: - new_policy.compositor_queue_priority = TaskQueue::HIGH_PRIORITY; - new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY; - new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY; - // NOTE these are nops due to the above. - block_expensive_loading_tasks = true; - block_expensive_timer_tasks = true; + new_policy.compositor_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + new_policy.loading_queue_policy.priority = TaskQueue::DISABLED_PRIORITY; + new_policy.timer_queue_policy.priority = TaskQueue::DISABLED_PRIORITY; + // NOTE this is a nop due to the above. + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; break; case UseCase::NONE: - // It's only safe to block tasks that are (likely to be) compositor - // driven. + // It's only safe to block tasks that if we are expecting a compositor + // driven gesture. if (touchstart_expected_soon && AnyThread().last_gesture_was_compositor_driven) { - block_expensive_loading_tasks = true; - block_expensive_timer_tasks = true; + expensive_task_policy = ExpensiveTaskPolicy::BLOCK; } break; case UseCase::LOADING: - new_policy.loading_queue_priority = TaskQueue::HIGH_PRIORITY; - new_policy.default_queue_priority = TaskQueue::HIGH_PRIORITY; + new_policy.loading_queue_policy.priority = TaskQueue::HIGH_PRIORITY; + new_policy.default_queue_policy.priority = TaskQueue::HIGH_PRIORITY; break; default: NOTREACHED(); } - if (!MainThreadOnly().expensive_task_blocking_allowed) { - block_expensive_loading_tasks = false; - block_expensive_timer_tasks = false; + if (expensive_task_policy == ExpensiveTaskPolicy::BLOCK && + (!MainThreadOnly().expensive_task_blocking_allowed || + !MainThreadOnly().have_seen_a_begin_main_frame || + MainThreadOnly().navigation_task_expected_count > 0)) { + expensive_task_policy = ExpensiveTaskPolicy::RUN; } - // Don't block expensive tasks unless we have actually seen something. - if (!MainThreadOnly().have_seen_a_begin_main_frame) { - block_expensive_loading_tasks = false; - block_expensive_timer_tasks = false; + switch (expensive_task_policy) { + case ExpensiveTaskPolicy::RUN: + break; + + case ExpensiveTaskPolicy::BLOCK: + if (loading_tasks_seem_expensive) + new_policy.loading_queue_policy.priority = TaskQueue::DISABLED_PRIORITY; + if (timer_tasks_seem_expensive) + new_policy.timer_queue_policy.priority = TaskQueue::DISABLED_PRIORITY; + break; + + case ExpensiveTaskPolicy::THROTTLE: + if (loading_tasks_seem_expensive) { + new_policy.loading_queue_policy.time_domain_type = + TimeDomainType::THROTTLED; + } + if (timer_tasks_seem_expensive) { + new_policy.timer_queue_policy.time_domain_type = + TimeDomainType::THROTTLED; + } + break; } - // Don't block expensive tasks if we are expecting a navigation. - if (MainThreadOnly().navigation_task_expected_count > 0) { - block_expensive_loading_tasks = false; - block_expensive_timer_tasks = false; - } - - // Only block expensive tasks if we have seen a touch start, i.e. don't block - // expensive timers on desktop because it's causing too many problems with - // legitimate webcontent using mousehandlers for various things. - // See http://crbug.com/570845 and http://crbug.com/570845 for details. - // TODO(alexclarke): Revisit the throttling decisions and mechanism. - if (!AnyThread().have_seen_touchstart) { - block_expensive_loading_tasks = false; - block_expensive_timer_tasks = false; - } - - if (block_expensive_loading_tasks && loading_tasks_seem_expensive) - new_policy.loading_queue_priority = TaskQueue::DISABLED_PRIORITY; - - if ((block_expensive_timer_tasks && timer_tasks_seem_expensive) || - MainThreadOnly().timer_queue_suspend_count != 0 || + if (MainThreadOnly().timer_queue_suspend_count != 0 || MainThreadOnly().timer_queue_suspended_when_backgrounded) { - new_policy.timer_queue_priority = TaskQueue::DISABLED_PRIORITY; + new_policy.timer_queue_policy.priority = TaskQueue::DISABLED_PRIORITY; } // Tracing is done before the early out check, because it's quite possible we @@ -766,30 +761,57 @@ "RendererScheduler.timer_tasks_seem_expensive", MainThreadOnly().timer_tasks_seem_expensive); + // TODO(alexclarke): Can we get rid of force update now? if (update_type == UpdateType::MAY_EARLY_OUT_IF_POLICY_UNCHANGED && new_policy == MainThreadOnly().current_policy) { return; } - compositor_task_runner_->SetQueuePriority( - new_policy.compositor_queue_priority); + ApplyTaskQueuePolicy(compositor_task_runner_.get(), + MainThreadOnly().current_policy.compositor_queue_policy, + new_policy.compositor_queue_policy); + for (const scoped_refptr<TaskQueue>& loading_queue : loading_task_runners_) { - loading_queue->SetQueuePriority(new_policy.loading_queue_priority); + ApplyTaskQueuePolicy(loading_queue.get(), + MainThreadOnly().current_policy.loading_queue_policy, + new_policy.loading_queue_policy); } + for (const scoped_refptr<TaskQueue>& timer_queue : timer_task_runners_) { - timer_queue->SetQueuePriority(new_policy.timer_queue_priority); + ApplyTaskQueuePolicy(timer_queue.get(), + MainThreadOnly().current_policy.timer_queue_policy, + new_policy.timer_queue_policy); } // TODO(alexclarke): We shouldn't have to prioritize the default queue, but it // appears to be necessary since the order of loading tasks and IPCs (which // are mostly dispatched on the default queue) need to be preserved. - helper_.DefaultTaskRunner()->SetQueuePriority( - new_policy.default_queue_priority); + ApplyTaskQueuePolicy(helper_.DefaultTaskRunner().get(), + MainThreadOnly().current_policy.default_queue_policy, + new_policy.default_queue_policy); DCHECK(compositor_task_runner_->IsQueueEnabled()); MainThreadOnly().current_policy = new_policy; } +void RendererSchedulerImpl::ApplyTaskQueuePolicy( + TaskQueue* task_queue, + const TaskQueuePolicy& old_task_queue_policy, + const TaskQueuePolicy& new_task_queue_policy) const { + if (old_task_queue_policy.priority != new_task_queue_policy.priority) + task_queue->SetQueuePriority(new_task_queue_policy.priority); + + if (old_task_queue_policy.time_domain_type != + new_task_queue_policy.time_domain_type) { + if (new_task_queue_policy.time_domain_type == TimeDomainType::THROTTLED) { + throttling_helper_->IncreaseThrottleRefCount(task_queue); + } else if (old_task_queue_policy.time_domain_type == + TimeDomainType::THROTTLED) { + throttling_helper_->DecreaseThrottleRefCount(task_queue); + } + } +} + bool RendererSchedulerImpl::InputSignalsSuggestGestureInProgress( base::TimeTicks now) const { base::TimeDelta unused_policy_duration;
diff --git a/components/scheduler/renderer/renderer_scheduler_impl.h b/components/scheduler/renderer/renderer_scheduler_impl.h index 52868c9..14b5aaa 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl.h +++ b/components/scheduler/renderer/renderer_scheduler_impl.h
@@ -106,26 +106,43 @@ return helper_.real_time_domain(); } - ThrottlingHelper* throttling_helper() { return &throttling_helper_; } + ThrottlingHelper* throttling_helper() { return throttling_helper_.get(); } private: friend class RendererSchedulerImplTest; friend class RendererSchedulerImplForTest; friend class RenderWidgetSchedulingState; - struct Policy { - Policy(); + enum class TimeDomainType { + REAL, + THROTTLED, + }; - TaskQueue::QueuePriority compositor_queue_priority; - TaskQueue::QueuePriority loading_queue_priority; - TaskQueue::QueuePriority timer_queue_priority; - TaskQueue::QueuePriority default_queue_priority; + struct TaskQueuePolicy { + TaskQueuePolicy() + : priority(TaskQueue::NORMAL_PRIORITY), + time_domain_type(TimeDomainType::REAL) {} + + TaskQueue::QueuePriority priority; + TimeDomainType time_domain_type; + + bool operator==(const TaskQueuePolicy& other) const { + return priority == other.priority && + time_domain_type == other.time_domain_type; + } + }; + + struct Policy { + TaskQueuePolicy compositor_queue_policy; + TaskQueuePolicy loading_queue_policy; + TaskQueuePolicy timer_queue_policy; + TaskQueuePolicy default_queue_policy; bool operator==(const Policy& other) const { - return compositor_queue_priority == other.compositor_queue_priority && - loading_queue_priority == other.loading_queue_priority && - timer_queue_priority == other.timer_queue_priority && - default_queue_priority == other.default_queue_priority; + return compositor_queue_policy == other.compositor_queue_policy && + loading_queue_policy == other.loading_queue_policy && + timer_queue_policy == other.timer_queue_policy && + default_queue_policy == other.default_queue_policy; } }; @@ -254,9 +271,13 @@ // current system state. Must be called from the main thread. base::TimeDelta EstimateLongestJankFreeTaskDuration() const; + void ApplyTaskQueuePolicy(TaskQueue* task_queue, + const TaskQueuePolicy& old_task_queue_policy, + const TaskQueuePolicy& new_task_queue_policy) const; + SchedulerHelper helper_; IdleHelper idle_helper_; - ThrottlingHelper throttling_helper_; + scoped_ptr<ThrottlingHelper> throttling_helper_; RenderWidgetSignals render_widget_scheduler_signals_; const scoped_refptr<TaskQueue> control_task_runner_;
diff --git a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc index 1e84f1a..66884e21 100644 --- a/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc +++ b/components/scheduler/renderer/renderer_scheduler_impl_unittest.cc
@@ -304,50 +304,15 @@ void ForceTouchStartToBeExpectedSoon() { scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + scheduler_->DidHandleInputEventOnCompositorThread( FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); clock_->Advance(priority_escalation_after_input_duration() * 2); scheduler_->ForceUpdatePolicy(); } - void EnableTaskBlocking() { - // Tasks are only ever blocked if we have seen a touch start. - // TODO(alexclarke): Revisit this. - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchStart), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchStart)); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchMove), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollBegin), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchMove)); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::GestureScrollEnd), - RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); - scheduler_->DidHandleInputEventOnCompositorThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd), - RendererScheduler::InputEventState::EVENT_FORWARDED_TO_MAIN_THREAD); - scheduler_->DidHandleInputEventOnMainThread( - FakeInputEvent(blink::WebInputEvent::TouchEnd)); - scheduler_->ForceUpdatePolicy(); - clock_->Advance(base::TimeDelta::FromSeconds(60)); - scheduler_->ForceUpdatePolicy(); - EXPECT_EQ(RendererScheduler::UseCase::NONE, CurrentUseCase()); - } - void SimulateExpensiveTasks( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { // RunUntilIdle won't actually run all of the SimpleTestTickClock::Advance @@ -451,6 +416,11 @@ base::TimeDelta begin_main_frame_duration) { clock_->Advance(begin_main_frame_duration); scheduler_->DidCommitFrameToCompositor(); + simulate_compositor_task_ran_ = true; + } + + bool SimulatedCompositorTaskPending() const { + return !simulate_compositor_task_ran_; } void SimulateTimerTask(base::TimeDelta duration) { @@ -489,6 +459,10 @@ return scheduler_->MainThreadOnly().estimated_next_frame_begin; } + int NavigationTaskExpectedCount() { + return scheduler_->MainThreadOnly().navigation_task_expected_count; + } + // Helper for posting several tasks of specific types. |task_descriptor| is a // string with space delimited task identifiers. The first letter of each // task identifier specifies the task type: @@ -597,6 +571,7 @@ scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_; scoped_refptr<base::SingleThreadTaskRunner> timer_task_runner_; bool simulate_timer_task_ran_; + bool simulate_compositor_task_ran_; DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest); }; @@ -2157,7 +2132,6 @@ ExpensiveLoadingTasksNotBlockedTillFirstBeginMainFrame) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); SimulateExpensiveTasks(loading_task_runner_); ForceTouchStartToBeExpectedSoon(); @@ -2191,7 +2165,6 @@ ExpensiveLoadingTasksNotBlockedIfNoTouchHandler) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(false); DoMainFrame(); SimulateExpensiveTasks(loading_task_runner_); @@ -2212,7 +2185,6 @@ ExpensiveTimerTaskBlocked_UseCase_NONE_PreviousCompositorGesture) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); DoMainFrame(); SimulateExpensiveTasks(timer_task_runner_); @@ -2233,7 +2205,6 @@ ExpensiveTimerTaskNotBlocked_UseCase_NONE_PreviousMainThreadGesture) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); DoMainFrame(); SimulateExpensiveTasks(timer_task_runner_); @@ -2268,7 +2239,6 @@ ExpensiveTimerTaskBlocked_UseCase_COMPOSITOR_GESTURE) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); DoMainFrame(); SimulateExpensiveTasks(timer_task_runner_); @@ -2291,7 +2261,6 @@ ExpensiveTimerTaskNotBlockedIfDissalowed_UseCase_COMPOSITOR_GESTURE) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetExpensiveTaskBlockingAllowed(false); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); DoMainFrame(); @@ -2313,31 +2282,9 @@ } TEST_F(RendererSchedulerImplTest, - ExpensiveTimerTaskNotBlockedIfTouchStartNotSeen) { - std::vector<std::string> run_order; - - scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); - DoMainFrame(); - SimulateExpensiveTasks(timer_task_runner_); - ForceTouchStartToBeExpectedSoon(); - - PostTestTasks(&run_order, "T1 D1"); - RunUntilIdle(); - - EXPECT_EQ(UseCase::NONE, ForceUpdatePolicyAndGetCurrentUseCase()); - EXPECT_TRUE(HaveSeenABeginMainframe()); - EXPECT_FALSE(LoadingTasksSeemExpensive()); - EXPECT_TRUE(TimerTasksSeemExpensive()); - EXPECT_TRUE(TouchStartExpectedSoon()); - EXPECT_THAT(run_order, testing::ElementsAre(std::string("T1"), - std::string("D1"))); -} - -TEST_F(RendererSchedulerImplTest, ExpensiveTimerTaskNotBlocked_IfBeginMainFrameNotExpectedSoon) { std::vector<std::string> run_order; - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); DoMainFrame(); SimulateExpensiveTasks(timer_task_runner_); @@ -2360,7 +2307,6 @@ ExpensiveLoadingTasksNotBlockedIfNavigationExpected) { std::vector<std::string> run_order; - EnableTaskBlocking(); DoMainFrame(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); SimulateExpensiveTasks(loading_task_runner_); @@ -2375,6 +2321,7 @@ EXPECT_TRUE(LoadingTasksSeemExpensive()); EXPECT_FALSE(TimerTasksSeemExpensive()); EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(1, NavigationTaskExpectedCount()); EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1"), std::string("D1"))); @@ -2391,6 +2338,7 @@ EXPECT_TRUE(LoadingTasksSeemExpensive()); EXPECT_FALSE(TimerTasksSeemExpensive()); EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(0, NavigationTaskExpectedCount()); EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); } @@ -2399,7 +2347,6 @@ ExpensiveLoadingTasksNotBlockedIfNavigationExpected_MultipleNavigations) { std::vector<std::string> run_order; - EnableTaskBlocking(); DoMainFrame(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); SimulateExpensiveTasks(loading_task_runner_); @@ -2415,6 +2362,7 @@ EXPECT_TRUE(LoadingTasksSeemExpensive()); EXPECT_FALSE(TimerTasksSeemExpensive()); EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(2, NavigationTaskExpectedCount()); EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1"), std::string("D1"))); @@ -2431,6 +2379,7 @@ EXPECT_TRUE(LoadingTasksSeemExpensive()); EXPECT_FALSE(TimerTasksSeemExpensive()); EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(1, NavigationTaskExpectedCount()); EXPECT_THAT(run_order, testing::ElementsAre(std::string("L1"), std::string("D1"))); @@ -2447,6 +2396,7 @@ EXPECT_TRUE(LoadingTasksSeemExpensive()); EXPECT_FALSE(TimerTasksSeemExpensive()); EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_EQ(0, NavigationTaskExpectedCount()); EXPECT_THAT(run_order, testing::ElementsAre(std::string("D1"))); } @@ -2454,7 +2404,6 @@ ExpensiveLoadingTasksNotBlockedDuringMainThreadGestures) { std::vector<std::string> run_order; - EnableTaskBlocking(); SimulateExpensiveTasks(loading_task_runner_); // Loading tasks should not be disabled during main thread user interactions. @@ -2473,7 +2422,6 @@ } TEST_F(RendererSchedulerImplTest, ModeratelyExpensiveTimer_NotBlocked) { - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, blink::WebInputEvent::TouchMove); @@ -2513,7 +2461,6 @@ TEST_F(RendererSchedulerImplTest, FourtyMsTimer_NotBlocked_CompositorScrolling) { - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); RunUntilIdle(); for (int i = 0; i < 20; i++) { @@ -2552,7 +2499,6 @@ TEST_F(RendererSchedulerImplTest, ExpensiveTimer_NotBlocked_UseCase_MAIN_THREAD_GESTURE) { - EnableTaskBlocking(); scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); SimulateMainThreadGestureStart(TouchEventPolicy::SEND_TOUCH_START, blink::WebInputEvent::TouchMove); @@ -2664,4 +2610,121 @@ scheduler_->EstimateLongestJankFreeTaskDuration()); } +namespace { +void SlowCountingTask(size_t* count, + base::SimpleTestTickClock* clock, + int task_duration, + scoped_refptr<base::SingleThreadTaskRunner> timer_queue) { + clock->Advance(base::TimeDelta::FromMilliseconds(task_duration)); + if (++(*count) < 500) { + timer_queue->PostTask(FROM_HERE, base::Bind(SlowCountingTask, count, clock, + task_duration, timer_queue)); + } +} +} + +TEST_F(RendererSchedulerImplTest, + SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_expensive) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + size_t count = 0; + // With the compositor task taking 10ms, there is not enough time to run this + // 7ms timer task in the 16ms frame. + scheduler_->TimerTaskRunner()->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 7, + scheduler_->TimerTaskRunner())); + + for (int i = 0; i < 1000; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + EXPECT_TRUE(scheduler_->TimerTaskRunner()->IsQueueEnabled()) << "i = " << i; + } + + // Task is throttled but not completely blocked. + EXPECT_EQ(13u, count); +} + +TEST_F(RendererSchedulerImplTest, + SYNCHRONIZED_GESTURE_TimerTaskThrottling_task_not_expensive) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + + size_t count = 0; + // With the compositor task taking 10ms, there is enough time to run this 6ms + // timer task in the 16ms frame. + scheduler_->TimerTaskRunner()->PostTask( + FROM_HERE, base::Bind(SlowCountingTask, &count, clock_.get(), 6, + scheduler_->TimerTaskRunner())); + + for (int i = 0; i < 1000; i++) { + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + simulate_compositor_task_ran_ = false; + compositor_task_runner_->PostTask( + FROM_HERE, + base::Bind(&RendererSchedulerImplTest::SimulateMainThreadCompositorTask, + base::Unretained(this), + base::TimeDelta::FromMilliseconds(10))); + + mock_task_runner_->RunTasksWhile( + base::Bind(&RendererSchedulerImplTest::SimulatedCompositorTaskPending, + base::Unretained(this))); + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, CurrentUseCase()) << "i = " << i; + EXPECT_TRUE(scheduler_->TimerTaskRunner()->IsQueueEnabled()) << "i = " << i; + } + + // Task is not throttled. + EXPECT_EQ(500u, count); +} + +TEST_F(RendererSchedulerImplTest, + ExpensiveTimerTaskBlocked_SYNCHRONIZED_GESTURE_TouchStartExpected) { + SimulateCompositorGestureStart(TouchEventPolicy::SEND_TOUCH_START); + SimulateExpensiveTasks(timer_task_runner_); + scheduler_->SetHasVisibleRenderWidgetWithTouchHandler(true); + ForceTouchStartToBeExpectedSoon(); + + // Bump us into SYNCHRONIZED_GESTURE. + scheduler_->DidHandleInputEventOnCompositorThread( + FakeInputEvent(blink::WebInputEvent::GestureScrollUpdate), + RendererScheduler::InputEventState::EVENT_CONSUMED_BY_COMPOSITOR); + + cc::BeginFrameArgs begin_frame_args = cc::BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, clock_->NowTicks(), base::TimeTicks(), + base::TimeDelta::FromMilliseconds(16), cc::BeginFrameArgs::NORMAL); + begin_frame_args.on_critical_path = true; + scheduler_->WillBeginFrame(begin_frame_args); + + EXPECT_EQ(UseCase::SYNCHRONIZED_GESTURE, + ForceUpdatePolicyAndGetCurrentUseCase()); + + EXPECT_TRUE(TimerTasksSeemExpensive()); + EXPECT_TRUE(TouchStartExpectedSoon()); + EXPECT_FALSE(scheduler_->TimerTaskRunner()->IsQueueEnabled()); +} + } // namespace scheduler
diff --git a/components/scheduler/renderer/throttling_helper.cc b/components/scheduler/renderer/throttling_helper.cc index 9a99001..b8b9b96 100644 --- a/components/scheduler/renderer/throttling_helper.cc +++ b/components/scheduler/renderer/throttling_helper.cc
@@ -32,30 +32,51 @@ } ThrottlingHelper::~ThrottlingHelper() { + // It's possible for queues to be still throttled, so we need to tidy up + // before unregistering the time domain. + for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { + TaskQueue* task_queue = map_entry.first; + task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + } + renderer_scheduler_->UnregisterTimeDomain(time_domain_.get()); } -void ThrottlingHelper::Throttle(TaskQueue* task_queue) { +void ThrottlingHelper::IncreaseThrottleRefCount(TaskQueue* task_queue) { DCHECK_NE(task_queue, task_runner_.get()); - throttled_queues_.insert(task_queue); - task_queue->SetTimeDomain(time_domain_.get()); - task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + std::pair<TaskQueueMap::iterator, bool> insert_result = + throttled_queues_.insert(std::make_pair(task_queue, 1)); - if (!task_queue->IsEmpty()) { - if (task_queue->HasPendingImmediateWork()) { - OnTimeDomainHasImmediateWork(); - } else { - OnTimeDomainHasDelayedWork(); + if (insert_result.second) { + // The insert was succesful so we need to throttle the queue. + task_queue->SetTimeDomain(time_domain_.get()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::MANUAL); + + if (!task_queue->IsEmpty()) { + if (task_queue->HasPendingImmediateWork()) { + OnTimeDomainHasImmediateWork(); + } else { + OnTimeDomainHasDelayedWork(); + } } + } else { + // An entry already existed in the map so we need to increment the refcount. + insert_result.first->second++; } } -void ThrottlingHelper::Unthrottle(TaskQueue* task_queue) { - throttled_queues_.erase(task_queue); +void ThrottlingHelper::DecreaseThrottleRefCount(TaskQueue* task_queue) { + TaskQueueMap::iterator iter = throttled_queues_.find(task_queue); - task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); - task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + if (iter != throttled_queues_.end() && --iter->second == 0) { + // The refcount has become zero, we need to unthrottle the queue. + throttled_queues_.erase(iter); + + task_queue->SetTimeDomain(renderer_scheduler_->real_time_domain()); + task_queue->SetPumpPolicy(TaskQueue::PumpPolicy::AUTO); + } } void ThrottlingHelper::OnTimeDomainHasImmediateWork() { @@ -88,7 +109,8 @@ base::TimeTicks now = tick_clock_->NowTicks(); time_domain_->AdvanceTo(now); - for (TaskQueue* task_queue : throttled_queues_) { + for (const TaskQueueMap::value_type& map_entry : throttled_queues_) { + TaskQueue* task_queue = map_entry.first; if (task_queue->IsEmpty()) continue;
diff --git a/components/scheduler/renderer/throttling_helper.h b/components/scheduler/renderer/throttling_helper.h index 69a47762..ad437c7 100644 --- a/components/scheduler/renderer/throttling_helper.h +++ b/components/scheduler/renderer/throttling_helper.h
@@ -30,8 +30,14 @@ void OnTimeDomainHasImmediateWork() override; void OnTimeDomainHasDelayedWork() override; - void Throttle(TaskQueue* task_queue); - void Unthrottle(TaskQueue* task_queue); + // Increments the throttled refcount and causes |task_queue| to be throttled + // if its not already throttled. + void IncreaseThrottleRefCount(TaskQueue* task_queue); + + // If the refcouint is non-zero it's decremented. If the throttled refcount + // becomes zero then |task_queue| is unthrottled. If the refcount was already + // zero this function does nothing. + void DecreaseThrottleRefCount(TaskQueue* task_queue); const VirtualTimeDomain* time_domain() const { return time_domain_.get(); } @@ -40,13 +46,15 @@ const scoped_refptr<TaskQueue>& task_runner() const { return task_runner_; } private: + using TaskQueueMap = std::map<TaskQueue*, size_t>; + void PumpThrottledTasks(); void MaybeSchedulePumpThrottledTasksLocked( const tracked_objects::Location& from_here, base::TimeTicks now, base::TimeTicks unthrottled_runtime); - std::set<TaskQueue*> throttled_queues_; + TaskQueueMap throttled_queues_; base::Closure forward_immediate_work_closure_; scoped_refptr<TaskQueue> task_runner_; RendererSchedulerImpl* renderer_scheduler_; // NOT OWNED
diff --git a/components/scheduler/renderer/throttling_helper_unittest.cc b/components/scheduler/renderer/throttling_helper_unittest.cc index f52a605a..e547c93 100644 --- a/components/scheduler/renderer/throttling_helper_unittest.cc +++ b/components/scheduler/renderer/throttling_helper_unittest.cc
@@ -23,6 +23,15 @@ namespace scheduler { +namespace { +void CountingTask(size_t* count, scoped_refptr<TaskQueue> timer_queue) { + if (++(*count) < 10) { + timer_queue->PostTask(FROM_HERE, + base::Bind(&CountingTask, count, timer_queue)); + } +} +} + class ThrottlingHelperTest : public testing::Test { public: ThrottlingHelperTest() {} @@ -45,6 +54,26 @@ scheduler_.reset(); } + void ExpectThrottled(scoped_refptr<TaskQueue> timer_queue) { + size_t count = 0; + timer_queue->PostTask(FROM_HERE, + base::Bind(&CountingTask, &count, timer_queue)); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_LT(count, 10u); + mock_task_runner_->RunUntilIdle(); + } + + void ExpectUnthrottled(scoped_refptr<TaskQueue> timer_queue) { + size_t count = 0; + timer_queue->PostTask(FROM_HERE, + base::Bind(&CountingTask, &count, timer_queue)); + + mock_task_runner_->RunForPeriod(base::TimeDelta::FromSeconds(1)); + EXPECT_EQ(count, 10u); + mock_task_runner_->RunUntilIdle(); + } + protected: scoped_ptr<base::SimpleTestTickClock> clock_; scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_; @@ -123,7 +152,7 @@ base::Bind(&TestTask, &run_times, clock_.get()), base::TimeDelta::FromMilliseconds(8300.0)); - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); mock_task_runner_->RunUntilIdle(); @@ -156,8 +185,8 @@ base::Bind(&TestTask, &run_times, clock_.get()), base::TimeDelta::FromMilliseconds(8300.0)); - throttling_helper_->Throttle(timer_queue_.get()); - throttling_helper_->Unthrottle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); mock_task_runner_->RunUntilIdle(); @@ -170,9 +199,32 @@ start_time + base::TimeDelta::FromMilliseconds(8300.0))); } +TEST_F(ThrottlingHelperTest, Refcount) { + ExpectUnthrottled(timer_queue_.get()); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); + + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); + + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + ExpectUnthrottled(timer_queue_); + + // Should be a NOP. + throttling_helper_->DecreaseThrottleRefCount(timer_queue_.get()); + ExpectUnthrottled(timer_queue_); + + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); + ExpectThrottled(timer_queue_); +} + TEST_F(ThrottlingHelperTest, ThrotlingAnEmptyQueueDoesNotPostPumpThrottledTasksLocked) { - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); EXPECT_TRUE(throttling_helper_->task_runner()->IsEmpty()); } @@ -181,7 +233,7 @@ std::vector<base::TimeTicks> run_times; // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick. - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); // Posting a task should trigger the pump. timer_queue_->PostTask(FROM_HERE, @@ -197,7 +249,7 @@ std::vector<base::TimeTicks> run_times; // Nothing is posted on timer_queue_ so PumpThrottledTasks will not tick. - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); // Posting a task should trigger the pump. timer_queue_->PostDelayedTask(FROM_HERE, @@ -222,7 +274,7 @@ TEST_F(ThrottlingHelperTest, SingleThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); base::TimeDelta delay(base::TimeDelta::FromMilliseconds(10)); timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); @@ -236,7 +288,7 @@ TEST_F(ThrottlingHelperTest, SingleFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5)); timer_queue_->PostDelayedTask(FROM_HERE, base::Bind(&NopTask), delay); @@ -250,7 +302,7 @@ TEST_F(ThrottlingHelperTest, TwoFutureThrottledTaskPumpedAndRunWithNoExtraneousMessageLoopTasks) { - throttling_helper_->Throttle(timer_queue_.get()); + throttling_helper_->IncreaseThrottleRefCount(timer_queue_.get()); std::vector<base::TimeTicks> run_times; base::TimeDelta delay(base::TimeDelta::FromSecondsD(15.5));
diff --git a/components/scheduler/renderer/web_frame_scheduler_impl.cc b/components/scheduler/renderer/web_frame_scheduler_impl.cc index bc40fa94f..c3d484b 100644 --- a/components/scheduler/renderer/web_frame_scheduler_impl.cc +++ b/components/scheduler/renderer/web_frame_scheduler_impl.cc
@@ -26,7 +26,7 @@ loading_task_queue_->UnregisterTaskQueue(); if (timer_task_queue_.get()) { - renderer_scheduler_->throttling_helper()->Unthrottle( + renderer_scheduler_->throttling_helper()->DecreaseThrottleRefCount( timer_task_queue_.get()); timer_task_queue_->UnregisterTaskQueue(); } @@ -58,7 +58,7 @@ timer_task_queue_ = renderer_scheduler_->NewTimerTaskRunner("frame_timer_tq"); if (page_in_background_) { - renderer_scheduler_->throttling_helper()->Throttle( + renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount( timer_task_queue_.get()); } timer_web_task_runner_.reset(new WebTaskRunnerImpl(timer_task_queue_)); @@ -82,9 +82,10 @@ return; if (page_in_background_) { - renderer_scheduler_->throttling_helper()->Throttle(timer_task_queue_.get()); + renderer_scheduler_->throttling_helper()->IncreaseThrottleRefCount( + timer_task_queue_.get()); } else { - renderer_scheduler_->throttling_helper()->Unthrottle( + renderer_scheduler_->throttling_helper()->DecreaseThrottleRefCount( timer_task_queue_.get()); } }
diff --git a/components/startup_metric_utils.gypi b/components/startup_metric_utils.gypi index 3fcd4a8..6a021818 100644 --- a/components/startup_metric_utils.gypi +++ b/components/startup_metric_utils.gypi
@@ -15,14 +15,11 @@ 'dependencies': [ '../base/base.gyp:base', '../base/base.gyp:base_prefs', - 'components.gyp:variations', ], 'include_dirs': [ '..', ], 'sources': [ - 'startup_metric_utils/browser/pre_read_field_trial_utils_win.cc', - 'startup_metric_utils/browser/pre_read_field_trial_utils_win.h', 'startup_metric_utils/browser/startup_metric_utils.cc', 'startup_metric_utils/browser/startup_metric_utils.h', ], @@ -52,11 +49,14 @@ 'dependencies': [ '../base/base.gyp:base', '../ipc/ipc.gyp:ipc', + 'components.gyp:variations', ], 'include_dirs': [ '..', ], 'sources': [ + 'startup_metric_utils/common/pre_read_field_trial_utils_win.cc', + 'startup_metric_utils/common/pre_read_field_trial_utils_win.h', 'startup_metric_utils/common/startup_metric_message_generator.cc', 'startup_metric_utils/common/startup_metric_message_generator.h', 'startup_metric_utils/common/startup_metric_messages.h',
diff --git a/components/startup_metric_utils/browser/BUILD.gn b/components/startup_metric_utils/browser/BUILD.gn index 64f0dd28..ef2fb13 100644 --- a/components/startup_metric_utils/browser/BUILD.gn +++ b/components/startup_metric_utils/browser/BUILD.gn
@@ -17,8 +17,6 @@ source_set("lib") { sources = [ - "pre_read_field_trial_utils_win.cc", - "pre_read_field_trial_utils_win.h", "startup_metric_utils.cc", "startup_metric_utils.h", ] @@ -26,7 +24,6 @@ deps = [ "//base", "//base:prefs", - "//components/variations", ] }
diff --git a/components/startup_metric_utils/browser/DEPS b/components/startup_metric_utils/browser/DEPS index 0dcfec3a..1c35d9c 100644 --- a/components/startup_metric_utils/browser/DEPS +++ b/components/startup_metric_utils/browser/DEPS
@@ -1,4 +1,3 @@ include_rules = [ - "+components/variations", "+content/public/browser", ]
diff --git a/components/startup_metric_utils/common/BUILD.gn b/components/startup_metric_utils/common/BUILD.gn index bfcb358..d9b2f09 100644 --- a/components/startup_metric_utils/common/BUILD.gn +++ b/components/startup_metric_utils/common/BUILD.gn
@@ -4,6 +4,8 @@ source_set("common") { sources = [ + "pre_read_field_trial_utils_win.cc", + "pre_read_field_trial_utils_win.h", "startup_metric_message_generator.cc", "startup_metric_message_generator.h", "startup_metric_messages.h", @@ -11,6 +13,7 @@ deps = [ "//base", + "//components/variations", "//ipc", ] }
diff --git a/components/startup_metric_utils/common/DEPS b/components/startup_metric_utils/common/DEPS index 1c40d98..131a835 100644 --- a/components/startup_metric_utils/common/DEPS +++ b/components/startup_metric_utils/common/DEPS
@@ -1,3 +1,4 @@ include_rules = [ + "+components/variations", "+ipc", ]
diff --git a/components/startup_metric_utils/browser/pre_read_field_trial_utils_win.cc b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc similarity index 98% rename from components/startup_metric_utils/browser/pre_read_field_trial_utils_win.cc rename to components/startup_metric_utils/common/pre_read_field_trial_utils_win.cc index d3de8c1..6aa82a19 100644 --- a/components/startup_metric_utils/browser/pre_read_field_trial_utils_win.cc +++ b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.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/startup_metric_utils/browser/pre_read_field_trial_utils_win.h" +#include "components/startup_metric_utils/common/pre_read_field_trial_utils_win.h" #include "base/callback.h" #include "base/memory/scoped_ptr.h"
diff --git a/components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.h similarity index 89% rename from components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h rename to components/startup_metric_utils/common/pre_read_field_trial_utils_win.h index 556d7ab..612f76b 100644 --- a/components/startup_metric_utils/browser/pre_read_field_trial_utils_win.h +++ b/components/startup_metric_utils/common/pre_read_field_trial_utils_win.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_STARTUP_METRIC_UTILS_FILE_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_ -#define COMPONENTS_STARTUP_METRIC_UTILS_FILE_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_ +#ifndef COMPONENTS_STARTUP_METRIC_UTILS_COMMON_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_ +#define COMPONENTS_STARTUP_METRIC_UTILS_COMMON_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_ #include <string> @@ -50,4 +50,4 @@ } // namespace startup_metric_utils -#endif // COMPONENTS_STARTUP_METRIC_UTILS_FILE_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_ +#endif // COMPONENTS_STARTUP_METRIC_UTILS_COMMON_PRE_READ_FIELD_TRIAL_UTILS_WIN_H_
diff --git a/components/sync_driver/about_sync_util.cc b/components/sync_driver/about_sync_util.cc index f9acf0f3..337d6b40 100644 --- a/components/sync_driver/about_sync_util.cc +++ b/components/sync_driver/about_sync_util.cc
@@ -391,7 +391,7 @@ GetTimeStr(token_status.next_token_request_time, "not scheduled")); last_synced.SetValue(service->GetLastSyncedTimeString()); - is_setup_complete.SetValue(service->HasSyncSetupCompleted()); + is_setup_complete.SetValue(service->IsFirstSetupComplete()); backend_initialization.SetValue( service->GetBackendInitializationStateString()); if (is_status_valid) {
diff --git a/components/sync_driver/about_sync_util_unittest.cc b/components/sync_driver/about_sync_util_unittest.cc index fcfa2b4..60ba5f2 100644 --- a/components/sync_driver/about_sync_util_unittest.cc +++ b/components/sync_driver/about_sync_util_unittest.cc
@@ -21,9 +21,7 @@ class SyncServiceMock : public sync_driver::FakeSyncService { public: - bool HasSyncSetupCompleted() const override { - return true; - } + bool IsFirstSetupComplete() const override { return true; } bool HasUnrecoverableError() const override { return true;
diff --git a/components/sync_driver/fake_sync_service.cc b/components/sync_driver/fake_sync_service.cc index 38b05ba..d1966e6 100644 --- a/components/sync_driver/fake_sync_service.cc +++ b/components/sync_driver/fake_sync_service.cc
@@ -18,7 +18,7 @@ FakeSyncService::~FakeSyncService() { } -bool FakeSyncService::HasSyncSetupCompleted() const { +bool FakeSyncService::IsFirstSetupComplete() const { return false; } @@ -72,8 +72,7 @@ syncer::ModelTypeSet chosen_types) { } -void FakeSyncService::SetSyncSetupCompleted() { -} +void FakeSyncService::SetFirstSetupComplete() {} bool FakeSyncService::IsFirstSetupInProgress() const { return false;
diff --git a/components/sync_driver/fake_sync_service.h b/components/sync_driver/fake_sync_service.h index 10fe104..5017e3f 100644 --- a/components/sync_driver/fake_sync_service.h +++ b/components/sync_driver/fake_sync_service.h
@@ -26,7 +26,7 @@ private: // sync_driver::SyncService: - bool HasSyncSetupCompleted() const override; + bool IsFirstSetupComplete() const override; bool IsSyncAllowed() const override; bool IsSyncActive() const override; void TriggerRefresh(const syncer::ModelTypeSet& types) override; @@ -43,7 +43,7 @@ syncer::ModelTypeSet GetPreferredDataTypes() const override; void OnUserChoseDatatypes(bool sync_everything, syncer::ModelTypeSet chosen_types) override; - void SetSyncSetupCompleted() override; + void SetFirstSetupComplete() override; bool IsFirstSetupInProgress() const override; void SetSetupInProgress(bool setup_in_progress) override; bool IsSetupInProgress() const override;
diff --git a/components/sync_driver/glue/sync_backend_host_core.h b/components/sync_driver/glue/sync_backend_host_core.h index 404732c..4bce014 100644 --- a/components/sync_driver/glue/sync_backend_host_core.h +++ b/components/sync_driver/glue/sync_backend_host_core.h
@@ -308,7 +308,7 @@ syncer::CancelationSignal release_request_context_signal_; syncer::CancelationSignal stop_syncing_signal_; - // Matches the value of SyncPref's HasSyncSetupCompleted() flag at init time. + // Matches the value of SyncPref's IsFirstSetupComplete() flag at init time. // Should not be used for anything except for UMAs and logging. const bool has_sync_setup_completed_;
diff --git a/components/sync_driver/glue/sync_backend_host_impl.cc b/components/sync_driver/glue/sync_backend_host_impl.cc index c222c12..2e73078 100644 --- a/components/sync_driver/glue/sync_backend_host_impl.cc +++ b/components/sync_driver/glue/sync_backend_host_impl.cc
@@ -61,7 +61,7 @@ invalidation_handler_registered_(false), weak_ptr_factory_(this) { core_ = new SyncBackendHostCore(name_, sync_folder, - sync_prefs_->HasSyncSetupCompleted(), + sync_prefs_->IsFirstSetupComplete(), weak_ptr_factory_.GetWeakPtr()); }
diff --git a/components/sync_driver/glue/sync_backend_host_impl_unittest.cc b/components/sync_driver/glue/sync_backend_host_impl_unittest.cc index 0d794aa5..1968558 100644 --- a/components/sync_driver/glue/sync_backend_host_impl_unittest.cc +++ b/components/sync_driver/glue/sync_backend_host_impl_unittest.cc
@@ -347,7 +347,7 @@ // Test the restart after setting up sync scenario. No enabled types should be // downloaded or cleaned. TEST_F(SyncBackendHostTest, Restart) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); syncer::ModelTypeSet all_but_nigori = enabled_types_; fake_manager_factory_->set_progress_marker_types(enabled_types_); fake_manager_factory_->set_initial_sync_ended_types(enabled_types_); @@ -375,7 +375,7 @@ // Test a sync restart scenario where some types had never finished configuring. // The partial types should be purged, then reconfigured properly. TEST_F(SyncBackendHostTest, PartialTypes) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); // Set sync manager behavior before passing it down. All types have progress // markers, but nigori and bookmarks are missing initial sync ended. syncer::ModelTypeSet partial_types(syncer::NIGORI, syncer::BOOKMARKS); @@ -414,7 +414,7 @@ // Test the behavior when we lose the sync db. Although we already have types // enabled, we should re-download all of them because we lost their data. TEST_F(SyncBackendHostTest, LostDB) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); // Initialization should fetch the Nigori node. Everything else should be // left untouched. InitializeBackend(true); @@ -578,7 +578,7 @@ // Test restarting the browser to newly supported datatypes. The new datatypes // should be downloaded on the configuration after backend initialization. TEST_F(SyncBackendHostTest, NewlySupportedTypes) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); // Set sync manager behavior before passing it down. All types have progress // markers and initial sync ended except the new types. syncer::ModelTypeSet old_types = enabled_types_; @@ -618,7 +618,7 @@ // types as well. Both partial and newly supported types should be downloaded // the configuration. TEST_F(SyncBackendHostTest, NewlySupportedTypesWithPartialTypes) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); // Set sync manager behavior before passing it down. All types have progress // markers and initial sync ended except the new types. syncer::ModelTypeSet old_types = enabled_types_; @@ -662,7 +662,7 @@ // Verify that downloading control types only downloads those types that do // not have initial sync ended set. TEST_F(SyncBackendHostTest, DownloadControlTypes) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); // Set sync manager behavior before passing it down. Experiments and device // info are new types without progress markers or initial sync ended, while // all other types have been fully downloaded and applied. @@ -720,7 +720,7 @@ // Test that configuration on restart sends the proper GU source. TEST_F(SyncBackendHostTest, DownloadControlTypesRestart) { - sync_prefs_->SetSyncSetupCompleted(); + sync_prefs_->SetFirstSetupComplete(); fake_manager_factory_->set_progress_marker_types(enabled_types_); fake_manager_factory_->set_initial_sync_ended_types(enabled_types_); InitializeBackend(true);
diff --git a/components/sync_driver/pref_names.cc b/components/sync_driver/pref_names.cc index 8b7afd96..550b927 100644 --- a/components/sync_driver/pref_names.cc +++ b/components/sync_driver/pref_names.cc
@@ -15,8 +15,8 @@ // 64-bit integer serialization of the base::Time of the last sync poll. const char kSyncLastPollTime[] = "sync.last_poll_time"; -// Boolean specifying whether the user finished setting up sync. -const char kSyncHasSetupCompleted[] = "sync.has_setup_completed"; +// Boolean specifying whether the user finished setting up sync at least once. +const char kSyncFirstSetupComplete[] = "sync.has_setup_completed"; // Boolean specifying whether sync has an auth error. const char kSyncHasAuthError[] = "sync.has_auth_error";
diff --git a/components/sync_driver/pref_names.h b/components/sync_driver/pref_names.h index 785d0c38..3209780 100644 --- a/components/sync_driver/pref_names.h +++ b/components/sync_driver/pref_names.h
@@ -16,7 +16,7 @@ extern const char kSyncLastSyncedTime[]; extern const char kSyncLastPollTime[]; extern const char kSyncHasAuthError[]; -extern const char kSyncHasSetupCompleted[]; +extern const char kSyncFirstSetupComplete[]; extern const char kSyncKeepEverythingSynced[]; extern const char kSyncAppList[];
diff --git a/components/sync_driver/startup_controller.cc b/components/sync_driver/startup_controller.cc index ec4424d4..f22f31f 100644 --- a/components/sync_driver/startup_controller.cc +++ b/components/sync_driver/startup_controller.cc
@@ -157,7 +157,7 @@ // fetch account details like encryption state to populate UI. Otherwise, // for performance reasons and maximizing parallelism at chrome startup, we // defer the heavy lifting for sync init until things have calmed down. - if (sync_prefs_->HasSyncSetupCompleted()) { + if (sync_prefs_->IsFirstSetupComplete()) { // For first time, defer start if data type hasn't requested sync to avoid // stressing browser start. If |first_start_| is false, most likely the // first attempt to start is intercepted by backup. When backup finishes,
diff --git a/components/sync_driver/startup_controller.h b/components/sync_driver/startup_controller.h index e4e59cdeb..c64275048 100644 --- a/components/sync_driver/startup_controller.h +++ b/components/sync_driver/startup_controller.h
@@ -20,7 +20,7 @@ namespace browser_sync { // Defines the type of behavior the sync engine should use. If configured for -// AUTO_START, the sync engine will automatically call SetSyncSetupCompleted() +// AUTO_START, the sync engine will automatically call SetFirstSetupComplete() // and start downloading data types as soon as sync credentials are available. // If configured for MANUAL_START, sync will not start until the user // completes sync setup, at which point the UI makes an explicit call to @@ -69,6 +69,7 @@ std::string GetBackendInitializationStateString() const; void OverrideFallbackTimeoutForTest(const base::TimeDelta& timeout); + private: enum StartUpDeferredOption { STARTUP_BACKEND_DEFERRED,
diff --git a/components/sync_driver/startup_controller_unittest.cc b/components/sync_driver/startup_controller_unittest.cc index 9447640..e11678db 100644 --- a/components/sync_driver/startup_controller_unittest.cc +++ b/components/sync_driver/startup_controller_unittest.cc
@@ -106,7 +106,7 @@ TEST_F(StartupControllerTest, Basic) { controller()->TryStart(); EXPECT_FALSE(started()); - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); controller()->TryStart(); EXPECT_FALSE(started()); signin()->set_account_id(kTestUser); @@ -126,7 +126,7 @@ // Test that sync doesn't start when not requested even if all other // conditons are met. TEST_F(StartupControllerTest, NotRequested) { - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); sync_prefs()->SetSyncRequested(false); signin()->set_account_id(kTestUser); token_service()->UpdateCredentials(kTestUser, kTestToken); @@ -138,7 +138,7 @@ // Test that sync doesn't when managed even if all other conditons are met. TEST_F(StartupControllerTest, Managed) { - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); sync_prefs()->SetManagedForTest(true); signin()->set_account_id(kTestUser); token_service()->UpdateCredentials(kTestUser, kTestToken); @@ -151,7 +151,7 @@ // Test that sync doesn't start until all conditions are met and a // data type triggers sync startup. TEST_F(StartupControllerTest, DataTypeTriggered) { - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); signin()->set_account_id(kTestUser); token_service()->UpdateCredentials(kTestUser, kTestToken); controller()->TryStart(); @@ -173,7 +173,7 @@ // Test that the fallback timer starts sync in the event all // conditions are met and no data type requests sync. TEST_F(StartupControllerTest, FallbackTimer) { - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); signin()->set_account_id(kTestUser); token_service()->UpdateCredentials(kTestUser, kTestToken); controller()->TryStart(); @@ -193,7 +193,7 @@ sync_prefs()->SetKeepEverythingSynced(false); sync_prefs()->SetPreferredDataTypes(syncer::UserTypes(), types); controller()->Reset(syncer::UserTypes()); - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); signin()->set_account_id(kTestUser); token_service()->UpdateCredentials(kTestUser, kTestToken); controller()->TryStart(); @@ -232,7 +232,7 @@ } TEST_F(StartupControllerTest, Reset) { - sync_prefs()->SetSyncSetupCompleted(); + sync_prefs()->SetFirstSetupComplete(); signin()->set_account_id(kTestUser); token_service()->UpdateCredentials(kTestUser, kTestToken); controller()->TryStart();
diff --git a/components/sync_driver/sync_error_controller.cc b/components/sync_driver/sync_error_controller.cc index 2db9277..48c9ee42 100644 --- a/components/sync_driver/sync_error_controller.cc +++ b/components/sync_driver/sync_error_controller.cc
@@ -15,9 +15,8 @@ } bool SyncErrorController::HasError() { - return service_->HasSyncSetupCompleted() && - service_->IsPassphraseRequired() && - service_->IsPassphraseRequiredForDecryption(); + return service_->IsFirstSetupComplete() && service_->IsPassphraseRequired() && + service_->IsPassphraseRequiredForDecryption(); } void SyncErrorController::AddObserver(Observer* observer) {
diff --git a/components/sync_driver/sync_prefs.cc b/components/sync_driver/sync_prefs.cc index 6f005ec8b..c448903 100644 --- a/components/sync_driver/sync_prefs.cc +++ b/components/sync_driver/sync_prefs.cc
@@ -36,7 +36,7 @@ // static void SyncPrefs::RegisterProfilePrefs( user_prefs::PrefRegistrySyncable* registry) { - registry->RegisterBooleanPref(prefs::kSyncHasSetupCompleted, false); + registry->RegisterBooleanPref(prefs::kSyncFirstSetupComplete, false); registry->RegisterBooleanPref(prefs::kSyncSuppressStart, false); registry->RegisterInt64Pref(prefs::kSyncLastSyncedTime, 0); registry->RegisterInt64Pref(prefs::kSyncLastPollTime, 0); @@ -105,7 +105,7 @@ DCHECK(CalledOnValidThread()); pref_service_->ClearPref(prefs::kSyncLastSyncedTime); pref_service_->ClearPref(prefs::kSyncLastPollTime); - pref_service_->ClearPref(prefs::kSyncHasSetupCompleted); + pref_service_->ClearPref(prefs::kSyncFirstSetupComplete); pref_service_->ClearPref(prefs::kSyncEncryptionBootstrapToken); pref_service_->ClearPref(prefs::kSyncKeystoreEncryptionBootstrapToken); pref_service_->ClearPref(prefs::kSyncPassphrasePrompted); @@ -121,14 +121,14 @@ // e.g. prefs::kSyncBookmarks. Is that really what we want? } -bool SyncPrefs::HasSyncSetupCompleted() const { +bool SyncPrefs::IsFirstSetupComplete() const { DCHECK(CalledOnValidThread()); - return pref_service_->GetBoolean(prefs::kSyncHasSetupCompleted); + return pref_service_->GetBoolean(prefs::kSyncFirstSetupComplete); } -void SyncPrefs::SetSyncSetupCompleted() { +void SyncPrefs::SetFirstSetupComplete() { DCHECK(CalledOnValidThread()); - pref_service_->SetBoolean(prefs::kSyncHasSetupCompleted, true); + pref_service_->SetBoolean(prefs::kSyncFirstSetupComplete, true); SetSyncRequested(true); }
diff --git a/components/sync_driver/sync_prefs.h b/components/sync_driver/sync_prefs.h index 7c71f21..c16710c 100644 --- a/components/sync_driver/sync_prefs.h +++ b/components/sync_driver/sync_prefs.h
@@ -75,8 +75,8 @@ // Getters and setters for global sync prefs. - bool HasSyncSetupCompleted() const; - void SetSyncSetupCompleted(); + bool IsFirstSetupComplete() const; + void SetFirstSetupComplete(); bool SyncHasAuthError() const; void SetSyncAuthError(bool error);
diff --git a/components/sync_driver/sync_prefs_unittest.cc b/components/sync_driver/sync_prefs_unittest.cc index f171266..e25ec61 100644 --- a/components/sync_driver/sync_prefs_unittest.cc +++ b/components/sync_driver/sync_prefs_unittest.cc
@@ -42,9 +42,9 @@ TEST_F(SyncPrefsTest, Basic) { SyncPrefs sync_prefs(&pref_service_); - EXPECT_FALSE(sync_prefs.HasSyncSetupCompleted()); - sync_prefs.SetSyncSetupCompleted(); - EXPECT_TRUE(sync_prefs.HasSyncSetupCompleted()); + EXPECT_FALSE(sync_prefs.IsFirstSetupComplete()); + sync_prefs.SetFirstSetupComplete(); + EXPECT_TRUE(sync_prefs.IsFirstSetupComplete()); EXPECT_TRUE(sync_prefs.IsSyncRequested()); sync_prefs.SetSyncRequested(false); @@ -209,21 +209,21 @@ TEST_F(SyncPrefsTest, ClearPreferences) { SyncPrefs sync_prefs(&pref_service_); - EXPECT_FALSE(sync_prefs.HasSyncSetupCompleted()); + EXPECT_FALSE(sync_prefs.IsFirstSetupComplete()); EXPECT_EQ(base::Time(), sync_prefs.GetLastSyncedTime()); EXPECT_TRUE(sync_prefs.GetEncryptionBootstrapToken().empty()); - sync_prefs.SetSyncSetupCompleted(); + sync_prefs.SetFirstSetupComplete(); sync_prefs.SetLastSyncedTime(base::Time::Now()); sync_prefs.SetEncryptionBootstrapToken("token"); - EXPECT_TRUE(sync_prefs.HasSyncSetupCompleted()); + EXPECT_TRUE(sync_prefs.IsFirstSetupComplete()); EXPECT_NE(base::Time(), sync_prefs.GetLastSyncedTime()); EXPECT_EQ("token", sync_prefs.GetEncryptionBootstrapToken()); sync_prefs.ClearPreferences(); - EXPECT_FALSE(sync_prefs.HasSyncSetupCompleted()); + EXPECT_FALSE(sync_prefs.IsFirstSetupComplete()); EXPECT_EQ(base::Time(), sync_prefs.GetLastSyncedTime()); EXPECT_TRUE(sync_prefs.GetEncryptionBootstrapToken().empty()); }
diff --git a/components/sync_driver/sync_service.h b/components/sync_driver/sync_service.h index d7ba6e5..e722444 100644 --- a/components/sync_driver/sync_service.h +++ b/components/sync_driver/sync_service.h
@@ -88,7 +88,7 @@ // that sync is currently running (due to delayed startup, unrecoverable // errors, or shutdown). See IsSyncActive below for checking whether sync // is actually running. - virtual bool HasSyncSetupCompleted() const = 0; + virtual bool IsFirstSetupComplete() const = 0; // Whether sync is allowed to start. Command line flags, platform-level // overrides, and account-level overrides are examples of reasons this @@ -149,7 +149,7 @@ // The user requests that sync start. This only actually starts sync if // IsSyncAllowed is true and the user is signed in. Once sync starts, - // other things such as HasSyncSetupCompleted being false can still prevent + // other things such as IsFirstSetupComplete being false can still prevent // it from moving into the "active" state. virtual void RequestStart() = 0; @@ -166,7 +166,7 @@ syncer::ModelTypeSet chosen_types) = 0; // Called whe Sync has been setup by the user and can be started. - virtual void SetSyncSetupCompleted() = 0; + virtual void SetFirstSetupComplete() = 0; // Returns true if initial sync setup is in progress (does not return true // if the user is customizing sync after already completing setup once).
diff --git a/components/test_runner/event_sender.cc b/components/test_runner/event_sender.cc index fdcc7f35..ffbd5569 100644 --- a/components/test_runner/event_sender.cc +++ b/components/test_runner/event_sender.cc
@@ -88,6 +88,11 @@ const int kButtonsInModifiers = WebMouseEvent::LeftButtonDown | WebMouseEvent::MiddleButtonDown | WebMouseEvent::RightButtonDown; +int modifiersWithButtons(int modifiers, int buttons) { + return (modifiers & ~kButtonsInModifiers) + | (buttons & kButtonsInModifiers); +} + void InitMouseEvent(WebInputEvent::Type t, WebMouseEvent::Button b, int current_buttons, @@ -98,8 +103,7 @@ WebMouseEvent* e) { e->type = t; e->button = b; - e->modifiers = (modifiers & ~kButtonsInModifiers) - | (current_buttons & kButtonsInModifiers); + e->modifiers = modifiersWithButtons(modifiers, current_buttons); e->x = pos.x; e->y = pos.y; e->globalX = pos.x; @@ -1281,7 +1285,7 @@ client_point, screen_point, current_drag_effects_allowed_, - modifiers_); + modifiersWithButtons(modifiers_, current_buttons_)); // Finish processing events. ReplaySavedEvents();
diff --git a/components/tracing/docs/heap_profiler.md b/components/tracing/docs/heap_profiler.md new file mode 100644 index 0000000..ba244ce --- /dev/null +++ b/components/tracing/docs/heap_profiler.md
@@ -0,0 +1,114 @@ +# Heap Profiling with MemoryInfra + +As of Chrome 48, MemoryInfra supports heap profiling. The core principle is +a solution that JustWorks™ on all platforms without patching or rebuilding, +intergrated with the chrome://tracing ecosystem. + +[TOC] + +## How to Use + + 1. Start Chrome with the `--enable-heap-profiling` switch. This will make + Chrome keep track of all allocations. + + 2. Grab a [MemoryInfra][memory-infra] trace. For best results, start tracing + first, and _then_ open a new tab that you want to trace. Furthermore, + enabling more categories (besides memory-infra) will yield more detailed + information in the heap profiler backtraces. + + 3. When the trace has been collected, select a heavy memory dump indicated by + a purple ![M][m-purple] dot. Heap dumps are only included in heavy memory + dumps. + + 4. In the analysis view, cells marked with a triple bar icon (☰) contain heap + dumps. Select such a cell. + + ![Cells containing a heap dump][cells-heap-dump] + + 5. Scroll down all the way to _Heap Details_. + + 6. Pinpoint the memory bug and live happily ever after. + +[memory-infra]: memory_infra.md +[m-purple]: https://drive.google.com/uc?id=0Bx14iZPZRgb5RFFGc0xZZEJWVFk +[cells-heap-dump]: https://drive.google.com/uc?id=0Bx14iZPZRgb5NGlJSFRONTFoWEU + +## Heap Details + +The heap details view contains a tree that represents the heap. The size of the +root node corresponds to the selected allocator cell. + +*** aside +The size value in the heap details view will not match the value in the selected +analysis view cell exactly. There are three reasons for this. First, the heap +profiler reports the memory that _the program requested_, whereas the allocator +reports the memory that it _actually allocated_ plus its own bookkeeping +overhead. Second, allocations that happen early --- before Chrome knows that +heap profiling is enabled --- are not captured by the heap profiler, but they +are reported by the allocator. Third, tracing overhead is not discounted by the +heap profiler. +*** + +The heap can be broken down in two ways: by _backtrace_ (marked with an ƒ), and +by _type_ (marked with a Ⓣ). When tracing is enabled, Chrome records trace +events, most of which appear in the flame chart in timeline view. At every +point in time these trace events form a pseudo stack, and a vertical slice +through the flame chart is like a backtrace. This corresponds to the ƒ nodes in +the heap details view. Hence enabling more tracing categories will give a more +detailed breakdown of the heap. + +The other way to break down the heap is by object type. At the moment this is +only supported for PartitionAlloc. + +*** aside +In official builds, only the most common type names are included due to binary +size concerns. Development builds have full type information. +*** + +To keep the trace log small, uninteresting information is omitted from heap +dumps. The long tail of small nodes is not dumped, but grouped in an `<other>` +node instead. Note that altough these small nodes are insignificant on their +own, together they can be responsible for a significant portion of the heap. The +`<other>` node is large in that case. + +## Example + +In the trace below, `ParseAuthorStyleSheet` is called at some point. + +![ParseAuthorStyleSheet pseudo stack][pseudo-stack] + +The pseudo stack of trace events corresponds to the tree of ƒ nodes below. Of +the 23.5 MiB of memory allocated with PartitionAlloc, 1.9 MiB was allocated +inside `ParseAuthorStyleSheet`, either directly, or at a deeper level (like +`CSSParserImpl::parseStyleSheet`). + +![Memory Allocated in ParseAuthorStyleSheet][break-down-by-backtrace] + +By expanding `ParseAuthorStyleSheet`, we can see which types were allocated +there. Of the 1.9 MiB, 371 KiB was spent on `ImmutableStylePropertySet`s, and +238 KiB was spent on `StringImpl`s. + +![ParseAuthorStyleSheet broken down by type][break-down-by-type] + +It is also possible to break down by type first, and then by backtrace. Below +we see that of the 23.5 MiB allocated with PartitionAlloc, 1 MiB is spent on +`Node`s, and about half of the memory spent on nodes was allocated in +`HTMLDocumentParser`. + +![The PartitionAlloc heap broken down by type first and then by backtrace][type-then-backtrace] + +Heap dump diffs are fully supported by trace viewer. Select a heavy memory dump +(a purple dot), then with the control key select a heavy memory dump earlier in +time. Below is a diff of theverge.com before and in the middle of loading ads. +We can see that 4 MiB were allocated when parsing the documents in all those +iframes, almost a megabyte of which was due to JavaScript. (Note that this is +memory allocated by PartitionAlloc alone, the total renderer memory increase was +around 72 MiB.) + +![Diff of The Verge before and after loading ads][diff] + +[pseudo-stack]: https://drive.google.com/uc?id=0Bx14iZPZRgb5M194Y2RqQjhoZkk +[break-down-by-backtrace]: https://drive.google.com/uc?id=0Bx14iZPZRgb5ZDRQdGNnNDNIazA +[break-down-by-type]: https://drive.google.com/uc?id=0Bx14iZPZRgb5THJMYlpyTEN2Q2s +[type-then-backtrace]: https://drive.google.com/uc?id=0Bx14iZPZRgb5UGZFX1pDUVpOLUU +[diff]: https://drive.google.com/uc?id=0Bx14iZPZRgb5UzNvMmVOa0RnQWs
diff --git a/components/tracing/docs/memory_infra.md b/components/tracing/docs/memory_infra.md new file mode 100644 index 0000000..58592dc --- /dev/null +++ b/components/tracing/docs/memory_infra.md
@@ -0,0 +1,168 @@ +# MemoryInfra + +MemoryInfra is a timeline-based profiling system integrated in chrome://tracing. +It aims at creating Chrome-scale memory measurement tooling so that on any +Chrome in the world --- desktop, mobile, Chrome OS or any other --- with the +click of a button you can understand where memory is being used in your system. + +[TOC] + +## Getting Started + + 1. Get a bleeding-edge or tip-of-tree build of Chrome. + + 2. [Record a trace as usual][record-trace]: open [chrome://tracing][tracing] + on Desktop Chrome or [chrome://inspect?tracing][inspect-tracing] to trace + Chrome for Android. + + 3. Make sure to enable the **memory-infra** category on the right. + + ![Tick the memory-infra checkbox when recording a trace.][memory-infra-box] + + 4. For now, some subsystems only work if Chrome is started with the + `--no-sandbox` flag. + <!-- TODO(primiano) TODO(ssid): https://crbug.com/461788 --> + +[record-trace]: https://sites.google.com/a/chromium.org/dev/developers/how-tos/trace-event-profiling-tool/recording-tracing-runs +[tracing]: chrome://tracing +[inspect-tracing]: chrome://inspect?tracing +[memory-infra-box]: https://drive.google.com/uc?export=view&id=0Bx14iZPZRgb5RHBJM1llY1g4cDg + +![Timeline View and Analysis View][tracing-views] + +After recording a trace, you will see the **timeline view**. Timeline view +shows: + + * Total resident memory grouped by process (at the top). + * Total resident memory grouped by subsystem (at the top). + * Allocated memory per subsystem for every process. + +Click one of the ![M][m-blue] dots to bring up the **analysis view**. Click +on a cell in analysis view to reveal more information about its subsystem. +PartitionAlloc for instance, has more details about its partitions. + +![Component details for PartitionAlloc][partalloc-details] + +The purple ![M][m-purple] dots represent heavy dumps. In these dumps, components +can provide more details than in the regular dumps. The full details of the +MemoryInfra UI are explained in its [design doc][mi-ui-doc]. + +[tracing-views]: https://drive.google.com/uc?export=view&id=0Bx14iZPZRgb5dFVYV2dtZmNxQjg +[m-blue]: https://drive.google.com/uc?export=view&id=0Bx14iZPZRgb5b1ZTcWY4em42a0U +[partalloc-details]: https://drive.google.com/uc?export=view&id=0Bx14iZPZRgb5eVpPR09yTW9Ebjg +[m-purple]: https://drive.google.com/uc?export=view&id=0Bx14iZPZRgb5RFFGc0xZZEJWVFk +[mi-ui-doc]: https://docs.google.com/document/d/1b5BSBEd1oB-3zj_CBAQWiQZ0cmI0HmjmXG-5iNveLqw/edit + +## Columns + +**Columns in blue** reflect the amount of actual physical memory used by the +process. This is what exerts memory pressure on the system. + + * **Total Resident**: (TODO: document this). + * **Peak Total Resident**: (TODO: document this). + * **PSS**: (TODO: document this). + * **Private Dirty**: (TODO: document this). + * **Swapped**: (TODO: document this). + +**Columns in black** reflect a best estimation of the the amount of physical +memory used by various subsystems of Chrome. + + * **Blink GC**: Memory used by [Oilpan][oilpan]. + * **CC**: Memory used by the compositor. + See [cc/memory][cc-memory] for the full details. + * **Discardable**: (TODO: document this). + * **Font Caches**: (TODO: document this). + * **GPU** and **GPU Memory Buffer**: GPU memory and RAM used for GPU purposes. + See [GPU Memory Tracing][gpu-memory]. + * **LevelDB**: (TODO: document this). + * **Malloc**: Memory allocated by calls to `malloc`, or `new` for most + non-Blink objects. + * **PartitionAlloc**: Memory allocated via [PartitionAlloc][partalloc]. + Blink objects that are not managed by Oilpan are allocated with + PartitionAlloc. + * **Skia**: (TODO: document this). + * **SQLite**: (TODO: document this). + * **V8**: (TODO: document this). + * **Web Cache**: (TODO: document this). + +The **tracing column in gray** reports memory that is used to collect all of the +above information. This memory would not be used if tracing were not enabled, +and it is discounted from malloc and the blue columns. + +<!-- TODO(primiano): Improve this. https://crbug.com/??? --> + +[oilpan]: /third_party/WebKit/Source/platform/heap/BlinkGCDesign.md +[cc-memory]: /cc/memory.md +[gpu-memory]: memory_infra_gpu.md +[partalloc]: /third_party/WebKit/Source/wtf/PartitionAlloc.md + +## Related Pages + + * [GPU Memory Tracing](memory_infra_gpu.md) + * [Heap Profiling with MemoryInfra](heap_profiler.md) + +## Rationale + +Another memory profiler? What is wrong with tool X? +Most of the existing tools: + + * Are hard to get working with Chrome. (Massive symbols, require OS-specific + tricks.) + * Lack Chrome-related context. + * Don't deal with multi-process scenarios. + +MemoryInfra leverages the existing tracing infrastructure in Chrome and provides +contextual data: + + * **It speaks Chrome slang.** + The Chromium codebase is instrumented. Its memory subsystems (allocators, + caches, etc.) uniformly report their stats into the trace in a way that can + be understood by Chrome developers. No more + `__gnu_cxx::new_allocator< std::_Rb_tree_node< std::pair< std::string const, base::Value*>>> ::allocate`. + * **Timeline data that can be correlated with other events.** + Did memory suddenly increase during a specific Blink / V8 / HTML parsing + event? Which subsystem increased? Did memory not go down as expected after + closing a tab? Which other threads were active during a bloat? + * **Works out of the box on desktop and mobile.** + No recompilations with unmaintained `GYP_DEFINES`, no time-consuming + symbolizations stages. All the logic is already into Chrome, ready to dump at + any time. + * **The same technology is used for telemetry and the ChromePerf dashboard.** + See [the slides][chromeperf-slides] and take a look at + [some ChromePerf dashboards][chromeperf] and + [telemetry documentation][telemetry]. + +[chromeperf-slides]: https://docs.google.com/presentation/d/1OyxyT1sfg50lA36A7ibZ7-bBRXI1kVlvCW0W9qAmM_0/present?slide=id.gde150139b_0_137 +[chromeperf]: https://chromeperf.appspot.com/report?sid=3b54e60c9951656574e19252fadeca846813afe04453c98a49136af4c8820b8d +[telemetry]: https://catapult.gsrc.io/telemetry + +## Development + +MemoryInfra is based on a simple and extensible architecture. See +[the slides][dp-slides] on how to get your subsystem reported in MemoryInfra, +or take a look at one of the existing examples such as +[malloc_dump_provider.cc][malloc-dp]. The crbug label is +[Hotlist-MemoryInfra][hotlist]. Don't hesitate to contact +[tracing@chromium.org][mailtracing] for questions and support. + +[dp-slides]: https://docs.google.com/presentation/d/1GI3HY3Mm5-Mvp6eZyVB0JiaJ-u3L1MMJeKHJg4lxjEI/present?slide=id.g995514d5c_1_45 +[malloc-dp]: https://chromium.googlesource.com/chromium/src.git/+/master/base/trace_event/malloc_dump_provider.cc +[hotlist]: https://code.google.com/p/chromium/issues/list?q=label:Hotlist-MemoryInfra +[mailtracing]: mailto:tracing@chromium.org + +## Design documents + +Architectural: + +<iframe width="100%" height="300px" src="https://docs.google.com/a/google.com/embeddedfolderview?id=0B3KuDeqD-lVJfmp0cW1VcE5XVWNxZndxelV5T19kT2NFSndYZlNFbkFpc3pSa2VDN0hlMm8"> +</iframe> + +Chrome-side design docs: + +<iframe width="100%" height="300px" src="https://docs.google.com/a/google.com/embeddedfolderview?id=0B3KuDeqD-lVJfndSa2dleUQtMnZDeWpPZk1JV0QtbVM5STkwWms4YThzQ0pGTmU1QU9kNVk"> +</iframe> + +Catapult-side design docs: + +<iframe width="100%" height="300px" src="https://docs.google.com/a/google.com/embeddedfolderview?id=0B3KuDeqD-lVJfm10bXd5YmRNWUpKOElOWS0xdU1tMmV1S3F4aHo0ZDJLTmtGRy1qVnQtVWM"> +</iframe>
diff --git a/components/tracing/docs/memory_infra_gpu.md b/components/tracing/docs/memory_infra_gpu.md new file mode 100644 index 0000000..c4e71ae --- /dev/null +++ b/components/tracing/docs/memory_infra_gpu.md
@@ -0,0 +1,93 @@ +# GPU Memory Tracing + +This is an overview of the GPU column in [MemoryInfra][memory-infra]. + +[TOC] + +## Quick Start + +If you want an overview of total GPU memory usage, select the GPU process' GPU +category and look at the _size_ column. (Not _effective size_.) + +![Look at the size column for total GPU memory][gpu-size-column] + +[memory-infra]: memory_infra.md +[gpu-size-column]: https://drive.google.com/uc?id=0Bx14iZPZRgb5bnpuZEJOR1FwNWs + +## In Depth + +GPU Memory in Chrome involves several different types of allocations. These +include, but are not limited to: + + * **Raw OpenGL Objects**: These objects are allocated by Chrome using the + OpenGL API. Chrome itself has handles to these objects, but the actual + backing memory may live in a variety of places (CPU side in the GPU process, + CPU side in the kernel, GPU side). Because most OpenGL operations occur over + IPC, communicating with Chrome's GPU process, these allocations are almost + always shared between a renderer or browser process and the GPU process. + * **GPU Memory Buffers**: These objects provide a chunk of writable memory + which can be handed off cross-process. While GPUMemoryBuffers represent a + platform-independent way to access this memory, they have a number of + possible platform-specific implementations (EGL surfaces on Linux, + IOSurfaces on Mac, or CPU side shared memory). Because of their cross + process use case, these objects will almost always be shared between a + renderer or browser process and the GPU process. + * **GLImages**: GLImages are a platform-independent abstraction around GPU + memory, similar to GPU Memory Buffers. In many cases, GLImages are created + from GPUMemoryBuffers. The primary difference is that GLImages are designed + to be bound to an OpenGL texture using the image extension. + +GPU Memory can be found across a number of different processes, in a few +different categories. + +Renderer or browser process: + + * **CC Category**: The CC category contains all resource allocations used in + the Chrome Compositor. When GPU rasterization is enabled, these resource + allocations will be GPU allocations as well. See also + [cc/memory][cc-memory]. + * **Skia/gpu_resources Category**: All GPU resources used by Skia. + * **GPUMemoryBuffer Category**: All GPUMemoryBuffers in use in the current + process. + +GPU process: + + * **GPU Category**: All GPU allocations, many shared with other processes. + * **GPUMemoryBuffer Category**: All GPUMemoryBuffers. + +## Example + +Many of the objects listed above are shared between multiple processes. +Consider a GL texture used by CC --- this texture is shared between a renderer +and the GPU process. Additionally, the texture may be backed by a GLImage which +was created from a GPUMemoryBuffer, which is also shared between the renderer +and GPU process. This means that the single texture may show up in the memory +logs of two different processes multiple times. + +To make things easier to understand, each GPU allocation is only ever "owned" +by a single process and category. For instance, in the above example, the +texture would be owned by the CC category of the renderer process. Each +allocation has (at least) two sizes recorded --- _size_ and _effective size_. +In the owning allocation, these two numbers will match: + +![Matching size and effective size][owner-size] + +Note that the allocation also gives information on what other processes it is +shared with (seen by hovering over the green arrow). If we navigate to the +other allocation (in this case, gpu/gl/textures/client_25/texture_216) we will +see a non-owning allocation. In this allocation the size is the same, but the +_effective size_ is 0: + +![Effective size of zero][non-owner-size] + +Other types, such as GPUMemoryBuffers and GLImages have similar sharing +patterns. + +When trying to get an overview of the absolute memory usage tied to the GPU, +you can look at the size column (not effective size) of just the GPU process' +GPU category. This will show all GPU allocations, whether or not they are owned +by another process. + +[cc-memory]: /cc/memory.md +[owner-size]: https://drive.google.com/uc?id=0Bx14iZPZRgb5ZVRROTExMmpkaTQ +[non-owner-size]: https://drive.google.com/uc?id=0Bx14iZPZRgb5SnNBYThUZVo0ajA
diff --git a/content/browser/android/download_controller_android_impl.cc b/content/browser/android/download_controller_android_impl.cc index feb8de3..a314d08a 100644 --- a/content/browser/android/download_controller_android_impl.cc +++ b/content/browser/android/download_controller_android_impl.cc
@@ -451,7 +451,9 @@ base::android::GetApplicationContext(), jurl.obj(), jmime_type.obj(), jfilename.obj(), jpath.obj(), item->GetReceivedBytes(), true, item->GetId(), item->PercentComplete(), time_delta.InMilliseconds(), - item->HasUserGesture()); + item->HasUserGesture(), + // Get all requirements that allows a download to be resumable. + !item->GetBrowserContext()->IsOffTheRecord()); break; } case DownloadItem::COMPLETE:
diff --git a/content/browser/android/download_controller_android_impl.h b/content/browser/android/download_controller_android_impl.h index 36c108e3..386135e 100644 --- a/content/browser/android/download_controller_android_impl.h +++ b/content/browser/android/download_controller_android_impl.h
@@ -30,7 +30,6 @@ #include "base/memory/scoped_vector.h" #include "base/memory/singleton.h" #include "content/public/browser/android/download_controller_android.h" -#include "content/public/browser/download_item.h" #include "net/cookies/cookie_monster.h" #include "url/gurl.h" @@ -44,8 +43,7 @@ class RenderViewHost; class WebContents; -class DownloadControllerAndroidImpl : public DownloadControllerAndroid, - public DownloadItem::Observer { +class DownloadControllerAndroidImpl : public DownloadControllerAndroid { public: static DownloadControllerAndroidImpl* GetInstance();
diff --git a/content/browser/background_sync/background_sync_browsertest.cc b/content/browser/background_sync/background_sync_browsertest.cc index a5de6ad..60d517e 100644 --- a/content/browser/background_sync/background_sync_browsertest.cc +++ b/content/browser/background_sync/background_sync_browsertest.cc
@@ -621,7 +621,8 @@ EXPECT_FALSE(GetRegistrationOneShot("delay")); } -IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, VerifyRetry) { +// Disabled due to flakiness. See https://crbug.com/578952. +IN_PROC_BROWSER_TEST_F(BackgroundSyncBrowserTest, DISABLED_VerifyRetry) { EXPECT_TRUE(RegisterServiceWorker()); EXPECT_TRUE(LoadTestPage(kDefaultTestURL)); // Control the page.
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 022f410c..9d02adfe 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -563,14 +563,15 @@ // the requests to cancel first, and then we start cancelling. We assert at // the end that there are no more to cancel since the context is about to go // away. - typedef std::vector<linked_ptr<ResourceLoader>> LoaderList; + typedef std::vector<scoped_ptr<ResourceLoader>> LoaderList; LoaderList loaders_to_cancel; for (LoaderMap::iterator i = pending_loaders_.begin(); i != pending_loaders_.end();) { - if (i->second->GetRequestInfo()->GetContext() == context) { - loaders_to_cancel.push_back(i->second); - IncrementOutstandingRequestsMemory(-1, *i->second->GetRequestInfo()); + ResourceLoader* loader = i->second.get(); + if (loader->GetRequestInfo()->GetContext() == context) { + loaders_to_cancel.push_back(std::move(i->second)); + IncrementOutstandingRequestsMemory(-1, *loader->GetRequestInfo()); pending_loaders_.erase(i++); } else { ++i; @@ -579,7 +580,7 @@ for (BlockedLoadersMap::iterator i = blocked_loaders_map_.begin(); i != blocked_loaders_map_.end();) { - BlockedLoadersList* loaders = i->second; + BlockedLoadersList* loaders = i->second.get(); if (loaders->empty()) { // This can happen if BlockRequestsForRoute() has been called for a route, // but we haven't blocked any matching requests yet. @@ -588,38 +589,35 @@ } ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo(); if (info->GetContext() == context) { + scoped_ptr<BlockedLoadersList> deleter(std::move(i->second)); blocked_loaders_map_.erase(i++); - for (BlockedLoadersList::const_iterator it = loaders->begin(); - it != loaders->end(); ++it) { - linked_ptr<ResourceLoader> loader = *it; + for (auto& loader : *loaders) { info = loader->GetRequestInfo(); // We make the assumption that all requests on the list have the same // ResourceContext. DCHECK_EQ(context, info->GetContext()); IncrementOutstandingRequestsMemory(-1, *info); - loaders_to_cancel.push_back(loader); + loaders_to_cancel.push_back(std::move(loader)); } - delete loaders; } else { ++i; } } #ifndef NDEBUG - for (LoaderList::iterator i = loaders_to_cancel.begin(); - i != loaders_to_cancel.end(); ++i) { + for (const auto& loader : loaders_to_cancel) { // There is no strict requirement that this be the case, but currently // downloads, streams, detachable requests, transferred requests, and // browser-owned requests are the only requests that aren't cancelled when // the associated processes go away. It may be OK for this invariant to // change in the future, but if this assertion fires without the invariant // changing, then it's indicative of a leak. - DCHECK((*i)->GetRequestInfo()->IsDownload() || - (*i)->GetRequestInfo()->is_stream() || - ((*i)->GetRequestInfo()->detachable_handler() && - (*i)->GetRequestInfo()->detachable_handler()->is_detached()) || - (*i)->GetRequestInfo()->GetProcessType() == PROCESS_TYPE_BROWSER || - (*i)->is_transferring()); + DCHECK(loader->GetRequestInfo()->IsDownload() || + loader->GetRequestInfo()->is_stream() || + (loader->GetRequestInfo()->detachable_handler() && + loader->GetRequestInfo()->detachable_handler()->is_detached()) || + loader->GetRequestInfo()->GetProcessType() == PROCESS_TYPE_BROWSER || + loader->is_transferring()); } #endif @@ -633,15 +631,13 @@ } // Validate that no more requests for this context were added. - for (LoaderMap::const_iterator i = pending_loaders_.begin(); - i != pending_loaders_.end(); ++i) { + for (const auto& loader : pending_loaders_) { // http://crbug.com/90971 - CHECK_NE(i->second->GetRequestInfo()->GetContext(), context); + CHECK_NE(loader.second->GetRequestInfo()->GetContext(), context); } - for (BlockedLoadersMap::const_iterator i = blocked_loaders_map_.begin(); - i != blocked_loaders_map_.end(); ++i) { - BlockedLoadersList* loaders = i->second; + for (const auto& blocked_loaders : blocked_loaders_map_) { + BlockedLoadersList* loaders = blocked_loaders.second.get(); if (!loaders->empty()) { ResourceRequestInfoImpl* info = loaders->front()->GetRequestInfo(); // http://crbug.com/90971 @@ -984,6 +980,27 @@ UMA_HISTOGRAM_LONG_TIMES( "Net.RequestTime2.ErrAborted", request_loading_time); + if (loader->request()->url().SchemeIsHTTPOrHTTPS()) { + UMA_HISTOGRAM_LONG_TIMES("Net.RequestTime2.ErrAborted.HttpScheme", + request_loading_time); + } else { + UMA_HISTOGRAM_LONG_TIMES("Net.RequestTime2.ErrAborted.NonHttpScheme", + request_loading_time); + } + + if (loader->request()->GetTotalReceivedBytes() > 0) { + UMA_HISTOGRAM_LONG_TIMES("Net.RequestTime2.ErrAborted.NetworkContent", + request_loading_time); + } else if (loader->request()->received_response_content_length() > 0) { + UMA_HISTOGRAM_LONG_TIMES( + "Net.RequestTime2.ErrAborted.NoNetworkContent.CachedContent", + request_loading_time); + } else { + UMA_HISTOGRAM_LONG_TIMES( + "Net.RequestTime2.ErrAborted.NoBytesRead", + request_loading_time); + } + BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&RecordAbortRapporOnUI, loader->request()->url(), @@ -1072,16 +1089,14 @@ // CancelBlockedRequestsForRoute while iterating over // blocked_loaders_map_, as it modifies it. std::set<GlobalRoutingID> ids; - for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin(); - iter != blocked_loaders_map_.end(); ++iter) { + for (const auto& blocked_loaders : blocked_loaders_map_) { std::pair<std::set<GlobalRoutingID>::iterator, bool> result = - ids.insert(iter->first); + ids.insert(blocked_loaders.first); // We should not have duplicates. DCHECK(result.second); } - for (std::set<GlobalRoutingID>::const_iterator iter = ids.begin(); - iter != ids.end(); ++iter) { - CancelBlockedRequestsForRoute(iter->child_id, iter->route_id); + for (const auto& routing_id : ids) { + CancelBlockedRequestsForRoute(routing_id.child_id, routing_id.route_id); } scheduler_.reset(); @@ -1175,8 +1190,8 @@ int route_id, int request_id, const ResourceHostMsg_Request& request_data, - const linked_ptr<ResourceLoader>& loader) { - ResourceRequestInfoImpl* info = loader->GetRequestInfo(); + LoaderMap::iterator iter) { + ResourceRequestInfoImpl* info = iter->second->GetRequestInfo(); GlobalRoutingID old_routing_id( request_data.transferred_request_child_id, info->GetRouteID()); GlobalRequestID old_request_id(request_data.transferred_request_child_id, @@ -1192,7 +1207,11 @@ bool should_update_count = info->counted_as_in_flight_request(); if (should_update_count) IncrementOutstandingRequestsCount(-1, info); - pending_loaders_.erase(old_request_id); + + DCHECK(pending_loaders_.find(old_request_id) == iter); + scoped_ptr<ResourceLoader> loader = std::move(iter->second); + ResourceLoader* loader_ptr = loader.get(); + pending_loaders_.erase(iter); // ResourceHandlers should always get state related to the request from the // ResourceRequestInfo rather than caching it locally. This lets us update @@ -1203,7 +1222,7 @@ // Update maps that used the old IDs, if necessary. Some transfers in tests // do not actually use a different ID, so not all maps need to be updated. - pending_loaders_[new_request_id] = loader; + pending_loaders_[new_request_id] = std::move(loader); IncrementOutstandingRequestsMemory(1, *info); if (should_update_count) IncrementOutstandingRequestsCount(1, info); @@ -1211,7 +1230,7 @@ if (blocked_loaders_map_.find(old_routing_id) != blocked_loaders_map_.end()) { blocked_loaders_map_[new_routing_id] = - blocked_loaders_map_[old_routing_id]; + std::move(blocked_loaders_map_[old_routing_id]); blocked_loaders_map_.erase(old_routing_id); } } @@ -1231,13 +1250,13 @@ } AppCacheInterceptor::CompleteCrossSiteTransfer( - loader->request(), + loader_ptr->request(), child_id, request_data.appcache_host_id, filter_); ServiceWorkerRequestHandler* handler = - ServiceWorkerRequestHandler::GetHandler(loader->request()); + ServiceWorkerRequestHandler::GetHandler(loader_ptr->request()); if (handler) { handler->CompleteCrossSiteTransfer( child_id, request_data.service_worker_provider_id); @@ -1285,10 +1304,9 @@ // If the request is transferring to a new process, we can update our // state and let it resume with its existing ResourceHandlers. if (it->second->is_transferring()) { - linked_ptr<ResourceLoader> deferred_loader = it->second; + ResourceLoader* deferred_loader = it->second.get(); UpdateRequestForTransfer(child_id, route_id, request_id, - request_data, deferred_loader); - + request_data, it); deferred_loader->CompleteTransfer(); } else { bad_message::ReceivedBadMessage( @@ -1883,15 +1901,14 @@ // Find the global ID of all matching elements. bool any_requests_transferring = false; std::vector<GlobalRequestID> matching_requests; - for (LoaderMap::const_iterator i = pending_loaders_.begin(); - i != pending_loaders_.end(); ++i) { - if (i->first.child_id != child_id) + for (const auto& loader : pending_loaders_) { + if (loader.first.child_id != child_id) continue; - ResourceRequestInfoImpl* info = i->second->GetRequestInfo(); + ResourceRequestInfoImpl* info = loader.second->GetRequestInfo(); - GlobalRequestID id(child_id, i->first.request_id); - DCHECK(id == i->first); + GlobalRequestID id(child_id, loader.first.request_id); + DCHECK(id == loader.first); // Don't cancel navigations that are expected to live beyond this process. if (IsTransferredNavigation(id)) any_requests_transferring = true; @@ -1940,14 +1957,12 @@ // CancelBlockedRequestsForRoute while iterating over // blocked_loaders_map_, as it modifies it. std::set<int> route_ids; - for (BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.begin(); - iter != blocked_loaders_map_.end(); ++iter) { - if (iter->first.child_id == child_id) - route_ids.insert(iter->first.route_id); + for (const auto& blocked_loaders : blocked_loaders_map_) { + if (blocked_loaders.first.child_id == child_id) + route_ids.insert(blocked_loaders.first.route_id); } - for (std::set<int>::const_iterator iter = route_ids.begin(); - iter != route_ids.end(); ++iter) { - CancelBlockedRequestsForRoute(child_id, *iter); + for (int route_id : route_ids) { + CancelBlockedRequestsForRoute(child_id, route_id); } } } @@ -2291,30 +2306,32 @@ return; } - linked_ptr<ResourceLoader> loader( + scoped_ptr<ResourceLoader> loader( new ResourceLoader(std::move(request), std::move(handler), this)); GlobalRoutingID id(info->GetGlobalRoutingID()); BlockedLoadersMap::const_iterator iter = blocked_loaders_map_.find(id); if (iter != blocked_loaders_map_.end()) { // The request should be blocked. - iter->second->push_back(loader); + iter->second->push_back(std::move(loader)); return; } - StartLoading(info, loader); + StartLoading(info, std::move(loader)); } void ResourceDispatcherHostImpl::StartLoading( ResourceRequestInfoImpl* info, - const linked_ptr<ResourceLoader>& loader) { + scoped_ptr<ResourceLoader> loader) { // TODO(pkasting): Remove ScopedTracker below once crbug.com/456331 is fixed. tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION( "456331 ResourceDispatcherHostImpl::StartLoading")); - pending_loaders_[info->GetGlobalRequestID()] = loader; - loader->StartRequest(); + ResourceLoader* loader_ptr = loader.get(); + pending_loaders_[info->GetGlobalRequestID()] = std::move(loader); + + loader_ptr->StartRequest(); } void ResourceDispatcherHostImpl::OnUserGesture(WebContentsImpl* contents) { @@ -2422,7 +2439,7 @@ GlobalRoutingID key(child_id, route_id); DCHECK(blocked_loaders_map_.find(key) == blocked_loaders_map_.end()) << "BlockRequestsForRoute called multiple time for the same RVH"; - blocked_loaders_map_[key] = new BlockedLoadersList(); + blocked_loaders_map_[key] = make_scoped_ptr(new BlockedLoadersList()); } void ResourceDispatcherHostImpl::ResumeBlockedRequestsForRoute(int child_id, @@ -2447,23 +2464,20 @@ return; } - BlockedLoadersList* loaders = iter->second; + BlockedLoadersList* loaders = iter->second.get(); + scoped_ptr<BlockedLoadersList> deleter(std::move(iter->second)); // Removing the vector from the map unblocks any subsequent requests. blocked_loaders_map_.erase(iter); - for (BlockedLoadersList::iterator loaders_iter = loaders->begin(); - loaders_iter != loaders->end(); ++loaders_iter) { - linked_ptr<ResourceLoader> loader = *loaders_iter; + for (scoped_ptr<ResourceLoader>& loader : *loaders) { ResourceRequestInfoImpl* info = loader->GetRequestInfo(); if (cancel_requests) { IncrementOutstandingRequestsMemory(-1, *info); } else { - StartLoading(info, loader); + StartLoading(info, std::move(loader)); } } - - delete loaders; } ResourceDispatcherHostImpl::HttpAuthRelationType
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h index 7492264..a64f34a 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.h +++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -21,7 +21,6 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "base/time/time.h" @@ -342,7 +341,7 @@ scoped_ptr<ResourceHandler> handler); void StartLoading(ResourceRequestInfoImpl* info, - const linked_ptr<ResourceLoader>& loader); + scoped_ptr<ResourceLoader> loader); // We keep track of how much memory each request needs and how many requests // are issued by each renderer. These are known as OustandingRequestStats. @@ -389,7 +388,7 @@ // It may be enhanced in the future to provide some kind of prioritization // mechanism. We should also consider a hashtable or binary tree if it turns // out we have a lot of things here. - typedef std::map<GlobalRequestID, linked_ptr<ResourceLoader> > LoaderMap; + using LoaderMap = std::map<GlobalRequestID, scoped_ptr<ResourceLoader>>; // Deletes the pending request identified by the iterator passed in. // This function will invalidate the iterator passed in. Callers should @@ -442,7 +441,7 @@ int route_id, int request_id, const ResourceHostMsg_Request& request_data, - const linked_ptr<ResourceLoader>& loader); + LoaderMap::iterator iter); void BeginRequest(int request_id, const ResourceHostMsg_Request& request_data, @@ -551,8 +550,9 @@ // True if the resource dispatcher host has been shut down. bool is_shutdown_; - typedef std::vector<linked_ptr<ResourceLoader> > BlockedLoadersList; - typedef std::map<GlobalRoutingID, BlockedLoadersList*> BlockedLoadersMap; + using BlockedLoadersList = std::vector<scoped_ptr<ResourceLoader>>; + using BlockedLoadersMap = + std::map<GlobalRoutingID, scoped_ptr<BlockedLoadersList>>; BlockedLoadersMap blocked_loaders_map_; // Maps the child_ids to the approximate number of bytes
diff --git a/content/browser/renderer_host/media/audio_output_device_enumerator.cc b/content/browser/renderer_host/media/audio_output_device_enumerator.cc index 70a4320..54c0531 100644 --- a/content/browser/renderer_host/media/audio_output_device_enumerator.cc +++ b/content/browser/renderer_host/media/audio_output_device_enumerator.cc
@@ -23,16 +23,19 @@ media::AudioDeviceNames device_names; audio_manager->GetAudioOutputDeviceNames(&device_names); + snapshot.has_actual_devices = !device_names.empty(); + // If no devices in enumeration, return a list with a default device - if (device_names.empty()) { - snapshot.push_back({media::AudioManagerBase::kDefaultDeviceId, - media::AudioManager::GetDefaultDeviceName(), - audio_manager->GetDefaultOutputStreamParameters()}); + if (!snapshot.has_actual_devices) { + snapshot.devices.push_back( + {media::AudioManagerBase::kDefaultDeviceId, + media::AudioManager::GetDefaultDeviceName(), + audio_manager->GetDefaultOutputStreamParameters()}); return snapshot; } for (const media::AudioDeviceName& name : device_names) { - snapshot.push_back( + snapshot.devices.push_back( {name.unique_id, name.device_name, name.unique_id == media::AudioManagerBase::kDefaultDeviceId ? audio_manager->GetDefaultOutputStreamParameters() @@ -43,6 +46,16 @@ } // namespace +AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration( + const std::vector<AudioOutputDeviceInfo>& devices, + bool has_actual_devices) + : devices(devices), has_actual_devices(has_actual_devices) {} + +AudioOutputDeviceEnumeration::AudioOutputDeviceEnumeration() + : has_actual_devices(false) {} + +AudioOutputDeviceEnumeration::~AudioOutputDeviceEnumeration() {} + AudioOutputDeviceEnumerator::AudioOutputDeviceEnumerator( media::AudioManager* audio_manager, CachePolicy cache_policy)
diff --git a/content/browser/renderer_host/media/audio_output_device_enumerator.h b/content/browser/renderer_host/media/audio_output_device_enumerator.h index 740e9c6..bf223a9 100644 --- a/content/browser/renderer_host/media/audio_output_device_enumerator.h +++ b/content/browser/renderer_host/media/audio_output_device_enumerator.h
@@ -43,7 +43,19 @@ media::AudioParameters output_params; }; -typedef std::vector<AudioOutputDeviceInfo> AudioOutputDeviceEnumeration; +// The result of an enumeration. It is used only in the browser side. +struct AudioOutputDeviceEnumeration { + public: + AudioOutputDeviceEnumeration( + const std::vector<AudioOutputDeviceInfo>& devices, + bool has_actual_devices); + AudioOutputDeviceEnumeration(); + ~AudioOutputDeviceEnumeration(); + + std::vector<AudioOutputDeviceInfo> devices; + bool has_actual_devices; +}; + typedef base::Callback<void(const AudioOutputDeviceEnumeration&)> AudioOutputDeviceEnumerationCB; @@ -59,11 +71,15 @@ // Does an enumeration and provides the results to the callback. // If there are no physical devices, the result contains a single entry with - // the default parameters provided by the underlying audio manager. + // the default parameters provided by the underlying audio manager and with + // the |has_actual_devices| field set to false. // The behavior with no physical devices is there to ease the transition // from the use of RenderThreadImpl::GetAudioHardwareConfig(), which always // provides default parameters, even if there are no devices. // See https://crbug.com/549125. + // Some audio managers always report a single device, regardless of the + // physical devices in the system. In this case the |has_actual_devices| field + // is set to true to differentiate from the case of no physical devices. void Enumerate(const AudioOutputDeviceEnumerationCB& callback); // Invalidates the current cache.
diff --git a/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc b/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc index de1aa34bc..ac6140c 100644 --- a/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc +++ b/content/browser/renderer_host/media/audio_output_device_enumerator_unittest.cc
@@ -11,6 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "base/single_thread_task_runner.h" +#include "base/strings/string_number_conversions.h" #include "base/thread_task_runner_handle.h" #include "content/browser/renderer_host/media/audio_output_device_enumerator.h" #include "content/public/test/test_browser_thread_bundle.h" @@ -25,24 +26,62 @@ namespace content { namespace { + class MockAudioManager : public media::FakeAudioManager { public: - MockAudioManager() : FakeAudioManager(&fake_audio_log_factory_) {} + MockAudioManager(size_t num_devices) + : FakeAudioManager(&fake_audio_log_factory_), num_devices_(num_devices) {} + MockAudioManager() : MockAudioManager(0) {} ~MockAudioManager() override {} - MOCK_METHOD1(GetAudioOutputDeviceNames, void(media::AudioDeviceNames*)); + + MOCK_METHOD1(MockGetAudioOutputDeviceNames, void(media::AudioDeviceNames*)); + + void GetAudioOutputDeviceNames( + media::AudioDeviceNames* device_names) override { + DCHECK(device_names->empty()); + MockGetAudioOutputDeviceNames(device_names); + if (num_devices_ > 0) { + device_names->push_back( + media::AudioDeviceName(AudioManager::GetDefaultDeviceName(), + AudioManagerBase::kDefaultDeviceId)); + for (size_t i = 0; i < num_devices_; i++) { + device_names->push_back( + media::AudioDeviceName("FakeDeviceName_" + base::IntToString(i), + "FakeDeviceId_" + base::IntToString(i))); + } + } + } private: media::FakeAudioLogFactory fake_audio_log_factory_; + size_t num_devices_; DISALLOW_COPY_AND_ASSIGN(MockAudioManager); }; + +// Fake audio manager that exposes only the default device +class OnlyDefaultDeviceAudioManager : public MockAudioManager { + public: + OnlyDefaultDeviceAudioManager() {} + ~OnlyDefaultDeviceAudioManager() override {} + void GetAudioOutputDeviceNames( + media::AudioDeviceNames* device_names) override { + DCHECK(device_names->empty()); + MockGetAudioOutputDeviceNames(device_names); + device_names->push_front( + media::AudioDeviceName(AudioManager::GetDefaultDeviceName(), + AudioManagerBase::kDefaultDeviceId)); + } + + private: + DISALLOW_COPY_AND_ASSIGN(OnlyDefaultDeviceAudioManager); +}; + } // namespace class AudioOutputDeviceEnumeratorTest : public ::testing::Test { public: AudioOutputDeviceEnumeratorTest() - : thread_bundle_(), task_runner_(base::ThreadTaskRunnerHandle::Get()) { - audio_manager_.reset(new MockAudioManager()); - } + : thread_bundle_(), task_runner_(base::ThreadTaskRunnerHandle::Get()) {} ~AudioOutputDeviceEnumeratorTest() override {} @@ -65,6 +104,14 @@ } } + void EnumerateCountCallback(size_t num_entries_expected, + bool actual_devices_expected, + const AudioOutputDeviceEnumeration& result) { + EXPECT_EQ(actual_devices_expected, result.has_actual_devices); + EXPECT_EQ(num_entries_expected, result.devices.size()); + task_runner_->PostTask(FROM_HERE, run_loop_.QuitClosure()); + } + void QuitCallback(const AudioOutputDeviceEnumeration& result) { MockCallback(result); task_runner_->PostTask(FROM_HERE, run_loop_.QuitClosure()); @@ -82,7 +129,8 @@ TEST_F(AudioOutputDeviceEnumeratorTest, EnumerateWithCache) { const int num_calls = 10; - EXPECT_CALL(*audio_manager_, GetAudioOutputDeviceNames(_)).Times(1); + audio_manager_.reset(new MockAudioManager()); + EXPECT_CALL(*audio_manager_, MockGetAudioOutputDeviceNames(_)).Times(1); EXPECT_CALL(*this, MockCallback(_)).Times(num_calls); AudioOutputDeviceEnumerator enumerator( audio_manager_.get(), @@ -95,7 +143,9 @@ TEST_F(AudioOutputDeviceEnumeratorTest, EnumerateWithNoCache) { const int num_calls = 10; - EXPECT_CALL(*audio_manager_, GetAudioOutputDeviceNames(_)).Times(num_calls); + audio_manager_.reset(new MockAudioManager()); + EXPECT_CALL(*audio_manager_, MockGetAudioOutputDeviceNames(_)) + .Times(num_calls); EXPECT_CALL(*this, MockCallback(_)).Times(num_calls); AudioOutputDeviceEnumerator enumerator( audio_manager_.get(), @@ -106,4 +156,54 @@ run_loop_.Run(); } +TEST_F(AudioOutputDeviceEnumeratorTest, EnumerateNoDevices) { + audio_manager_.reset(new MockAudioManager()); + EXPECT_CALL(*audio_manager_, MockGetAudioOutputDeviceNames(_)); + AudioOutputDeviceEnumerator enumerator( + audio_manager_.get(), + AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING); + enumerator.Enumerate( + base::Bind(&AudioOutputDeviceEnumeratorTest::EnumerateCountCallback, + base::Unretained(this), 1, false)); + run_loop_.Run(); +} + +TEST_F(AudioOutputDeviceEnumeratorTest, EnumerateOnlyDefaultDevice) { + audio_manager_.reset(new OnlyDefaultDeviceAudioManager()); + EXPECT_CALL(*audio_manager_, MockGetAudioOutputDeviceNames(_)); + AudioOutputDeviceEnumerator enumerator( + audio_manager_.get(), + AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING); + enumerator.Enumerate( + base::Bind(&AudioOutputDeviceEnumeratorTest::EnumerateCountCallback, + base::Unretained(this), 1, true)); + run_loop_.Run(); +} + +TEST_F(AudioOutputDeviceEnumeratorTest, EnumerateOneDevice) { + size_t num_devices = 1; + audio_manager_.reset(new MockAudioManager(num_devices)); + EXPECT_CALL(*audio_manager_, MockGetAudioOutputDeviceNames(_)); + AudioOutputDeviceEnumerator enumerator( + audio_manager_.get(), + AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING); + enumerator.Enumerate( + base::Bind(&AudioOutputDeviceEnumeratorTest::EnumerateCountCallback, + base::Unretained(this), num_devices + 1, true)); + run_loop_.Run(); +} + +TEST_F(AudioOutputDeviceEnumeratorTest, EnumerateMultipleDevices) { + size_t num_devices = 5; + audio_manager_.reset(new MockAudioManager(num_devices)); + EXPECT_CALL(*audio_manager_, MockGetAudioOutputDeviceNames(_)); + AudioOutputDeviceEnumerator enumerator( + audio_manager_.get(), + AudioOutputDeviceEnumerator::CACHE_POLICY_NO_CACHING); + enumerator.Enumerate( + base::Bind(&AudioOutputDeviceEnumeratorTest::EnumerateCountCallback, + base::Unretained(this), num_devices + 1, true)); + run_loop_.Run(); +} + } // namespace content
diff --git a/content/browser/renderer_host/media/audio_renderer_host.cc b/content/browser/renderer_host/media/audio_renderer_host.cc index 49e395bd..d469d34 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.cc +++ b/content/browser/renderer_host/media/audio_renderer_host.cc
@@ -840,9 +840,9 @@ const std::string& device_id, const GURL& security_origin, const OutputDeviceInfoCB& callback, - const AudioOutputDeviceEnumeration& device_infos) { + const AudioOutputDeviceEnumeration& enumeration) { DCHECK_CURRENTLY_ON(BrowserThread::IO); - for (const AudioOutputDeviceInfo& device_info : device_infos) { + for (const AudioOutputDeviceInfo& device_info : enumeration.devices) { if (device_id.empty()) { if (device_info.unique_id == media::AudioManagerBase::kDefaultDeviceId) { callback.Run(true, device_info);
diff --git a/content/browser/renderer_host/media/audio_renderer_host.h b/content/browser/renderer_host/media/audio_renderer_host.h index ce32fb16..e549df20 100644 --- a/content/browser/renderer_host/media/audio_renderer_host.h +++ b/content/browser/renderer_host/media/audio_renderer_host.h
@@ -231,7 +231,7 @@ void TranslateDeviceID(const std::string& device_id, const GURL& gurl_security_origin, const OutputDeviceInfoCB& callback, - const AudioOutputDeviceEnumeration& device_infos); + const AudioOutputDeviceEnumeration& enumeration); // Helper method to check if the authorization procedure for stream // |stream_id| has started.
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc index 49c828b..f602e8d 100644 --- a/content/browser/renderer_host/media/media_stream_manager.cc +++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -739,10 +739,8 @@ DVLOG(1) << "AudioOutputDevicesEnumerated()"; StreamDeviceInfoArray device_infos; - // If the enumeration contains only one entry, it means there are no devices. - // The single entry contains default parameters from the audio manager. - if (device_enumeration.size() > 1) { - for (const auto& entry : device_enumeration) { + if (device_enumeration.has_actual_devices) { + for (const auto& entry : device_enumeration.devices) { StreamDeviceInfo device_info(MEDIA_DEVICE_AUDIO_OUTPUT, entry.device_name, entry.unique_id); device_infos.push_back(device_info);
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc index e0001b8..e2d1177 100644 --- a/content/browser/tracing/background_tracing_manager_browsertest.cc +++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -184,9 +184,18 @@ } } +#if defined(THREAD_SANITIZER) +// There's a race in ConvertableToTraceFormat that's hard to suppress, +// see http://crbug.com/559117. +#define MAYBE_CallTriggersMoreThanOnceOnlyGatherOnce \ + DISABLED_CallTriggersMoreThanOnceOnlyGatherOnce +#else +#define MAYBE_CallTriggersMoreThanOnceOnlyGatherOnce \ + CallTriggersMoreThanOnceOnlyGatherOnce +#endif // This tests triggering more than once still only gathers once. IN_PROC_BROWSER_TEST_F(BackgroundTracingManagerBrowserTest, - CallTriggersMoreThanOnceOnlyGatherOnce) { + MAYBE_CallTriggersMoreThanOnceOnlyGatherOnce) { { SetupBackgroundTracingManager();
diff --git a/content/content_shell.gypi b/content/content_shell.gypi index 35e849be..3147271f 100644 --- a/content/content_shell.gypi +++ b/content/content_shell.gypi
@@ -470,11 +470,6 @@ }, }, 'conditions': [ - ['OS=="win" and win_use_allocator_shim==1', { - 'dependencies': [ - '../base/allocator/allocator.gyp:allocator', - ], - }], ['OS=="win"', { 'sources': [ 'shell/app/shell.rc', @@ -488,19 +483,26 @@ }, }, }, - }], # OS=="win" - ['OS == "win"', { 'dependencies': [ '../sandbox/sandbox.gyp:sandbox', ], + 'conditions': [ + ['win_use_allocator_shim==1', { + 'dependencies': [ + '../base/allocator/allocator.gyp:allocator', + ], + }], + ['win_console_app==1', { + 'defines': ['WIN_CONSOLE_APP'], + }, { # else win_console_app==0 + 'msvs_settings': { + 'VCLinkerTool': { + 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS + }, + }, + }], + ], }], # OS=="win" - ['OS=="win" and asan==0', { - 'msvs_settings': { - 'VCLinkerTool': { - 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS - }, - }, - }], # OS=="win" and asan==0 ['OS=="mac"', { 'product_name': '<(content_shell_product_name)', 'dependencies!': [ @@ -927,7 +929,7 @@ }], ], }, - 'includes': [ + 'includes': [ '../build/android/v8_external_startup_data_arch_suffix.gypi', '../build/java_apk.gypi', ],
diff --git a/content/public/android/java/src/org/chromium/content/browser/DownloadController.java b/content/public/android/java/src/org/chromium/content/browser/DownloadController.java index 98c16e1..b190609 100644 --- a/content/public/android/java/src/org/chromium/content/browser/DownloadController.java +++ b/content/public/android/java/src/org/chromium/content/browser/DownloadController.java
@@ -134,9 +134,10 @@ * network stack use custom notification to display the progress of downloads. */ @CalledByNative - private void onDownloadUpdated(Context context, String url, String mimeType, - String filename, String path, long contentLength, boolean successful, int downloadId, - int percentCompleted, long timeRemainingInMs, boolean hasUserGesture) { + private void onDownloadUpdated(Context context, String url, String mimeType, String filename, + String path, long contentLength, boolean successful, int downloadId, + int percentCompleted, long timeRemainingInMs, boolean hasUserGesture, + boolean isResumable) { if (sDownloadNotificationService != null) { DownloadInfo downloadInfo = new DownloadInfo.Builder() .setUrl(url) @@ -151,6 +152,7 @@ .setPercentCompleted(percentCompleted) .setTimeRemainingInMillis(timeRemainingInMs) .setHasUserGesture(hasUserGesture) + .setIsResumable(isResumable) .build(); sDownloadNotificationService.onDownloadUpdated(downloadInfo); }
diff --git a/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java b/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java index 069c6dea..095a3f6 100644 --- a/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java +++ b/content/public/android/java/src/org/chromium/content/browser/DownloadInfo.java
@@ -25,6 +25,7 @@ private final boolean mIsSuccessful; private final int mPercentCompleted; private final long mTimeRemainingInMillis; + private final boolean mIsResumable; private DownloadInfo(Builder builder) { mUrl = builder.mUrl; @@ -44,6 +45,7 @@ mContentDisposition = builder.mContentDisposition; mPercentCompleted = builder.mPercentCompleted; mTimeRemainingInMillis = builder.mTimeRemainingInMillis; + mIsResumable = builder.mIsResumable; } public String getUrl() { @@ -117,6 +119,13 @@ return mTimeRemainingInMillis; } + public boolean isResumable() { + return mIsResumable; + } + + /** + * Helper class for building the DownloadInfo object. + */ public static class Builder { private String mUrl; private String mUserAgent; @@ -135,6 +144,7 @@ private String mContentDisposition; private int mPercentCompleted = -1; private long mTimeRemainingInMillis; + private boolean mIsResumable = true; public Builder setUrl(String url) { mUrl = url; @@ -222,6 +232,11 @@ return this; } + public Builder setIsResumable(boolean isResumable) { + mIsResumable = isResumable; + return this; + } + public DownloadInfo build() { return new DownloadInfo(this); } @@ -233,8 +248,7 @@ */ public static Builder fromDownloadInfo(final DownloadInfo downloadInfo) { Builder builder = new Builder(); - builder - .setUrl(downloadInfo.getUrl()) + builder.setUrl(downloadInfo.getUrl()) .setUserAgent(downloadInfo.getUserAgent()) .setMimeType(downloadInfo.getMimeType()) .setCookie(downloadInfo.getCookie()) @@ -250,7 +264,8 @@ .setIsGETRequest(downloadInfo.isGETRequest()) .setIsSuccessful(downloadInfo.isSuccessful()) .setPercentCompleted(downloadInfo.getPercentCompleted()) - .setTimeRemainingInMillis(downloadInfo.getTimeRemainingInMillis()); + .setTimeRemainingInMillis(downloadInfo.getTimeRemainingInMillis()) + .setIsResumable(downloadInfo.isResumable()); return builder; }
diff --git a/content/public/browser/android/download_controller_android.h b/content/public/browser/android/download_controller_android.h index 859a8a0..08fe6f7 100644 --- a/content/public/browser/android/download_controller_android.h +++ b/content/public/browser/android/download_controller_android.h
@@ -7,6 +7,7 @@ #include "base/callback.h" #include "content/common/content_export.h" +#include "content/public/browser/download_item.h" #include "content/public/common/context_menu_params.h" namespace content { @@ -15,7 +16,7 @@ // Interface to request GET downloads and send notifications for POST // downloads. -class CONTENT_EXPORT DownloadControllerAndroid { +class CONTENT_EXPORT DownloadControllerAndroid : public DownloadItem::Observer { public: // Returns the singleton instance of the DownloadControllerAndroid. static DownloadControllerAndroid* Get(); @@ -57,7 +58,7 @@ virtual void SetApproveFileAccessRequestForTesting(bool approve) {}; protected: - virtual ~DownloadControllerAndroid() {}; + ~DownloadControllerAndroid() override {}; static DownloadControllerAndroid* download_controller_; };
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 32c4a35c..4329349 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -17,7 +17,7 @@ // Downloads resumption will be controllable via a flag until it's enabled // permanently. See https://crbug.com/7648 const base::Feature kDownloadResumption{"DownloadResumption", - base::FEATURE_ENABLED_BY_DEFAULT}; + base::FEATURE_DISABLED_BY_DEFAULT}; // The Experimental Framework for controlling access to API experiments. const base::Feature kExperimentalFramework{"ExperimentalFramework",
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index d232069..c6f4aca 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -1196,8 +1196,12 @@ GLuint texture_target = kGLTextureExternalOES; GLuint texture_id_ref = gl->CreateAndConsumeTextureCHROMIUM( texture_target, texture_mailbox_.name); + const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM(); gl->Flush(); - gpu::SyncToken texture_mailbox_sync_token(gl->InsertSyncPointCHROMIUM()); + + gpu::SyncToken texture_mailbox_sync_token; + gl->GenUnverifiedSyncTokenCHROMIUM(fence_sync, + texture_mailbox_sync_token.GetData()); scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture( media::PIXEL_FORMAT_ARGB,
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn index c07b2156..0fb2f9d7 100644 --- a/content/shell/BUILD.gn +++ b/content/shell/BUILD.gn
@@ -5,6 +5,7 @@ import("//build/config/features.gni") import("//build/config/sanitizers/sanitizers.gni") import("//build/config/ui.gni") +import("//build/config/win/console_app.gni") import("//build/config/win/manifest.gni") import("//tools/grit/repack.gni") import("//tools/grit/grit_rule.gni") @@ -412,6 +413,8 @@ "app/shell_main.cc", ] + defines = [] + deps = [ ":content_shell_lib", ":pak", @@ -422,7 +425,10 @@ if (is_win) { deps += [ "//sandbox" ] - if (!is_asan) { + if (win_console_app) { + defines += [ "WIN_CONSOLE_APP" ] + } else { + # Set /SUBSYSTEM:WINDOWS unless a console build has been requested. configs -= [ "//build/config/win:console" ] configs += [ "//build/config/win:windowed" ] }
diff --git a/content/shell/app/shell_main.cc b/content/shell/app/shell_main.cc index 5814a28f..8d82d12 100644 --- a/content/shell/app/shell_main.cc +++ b/content/shell/app/shell_main.cc
@@ -17,11 +17,9 @@ #if defined(OS_WIN) -#if !defined(ADDRESS_SANITIZER) +#if !defined(WIN_CONSOLE_APP) int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) { #else -// The AddressSanitizer build should be a console program as it prints out stuff -// on stderr. int main() { HINSTANCE instance = GetModuleHandle(NULL); #endif
diff --git a/ios/chrome/browser/sync/sync_setup_service.cc b/ios/chrome/browser/sync/sync_setup_service.cc index bdef1e7..1e25f3b 100644 --- a/ios/chrome/browser/sync/sync_setup_service.cc +++ b/ios/chrome/browser/sync/sync_setup_service.cc
@@ -163,13 +163,13 @@ // OR // 2. User is not signed in or has disabled sync. return !sync_service_->CanSyncStart() || - sync_service_->HasSyncSetupCompleted(); + sync_service_->IsFirstSetupComplete(); } void SyncSetupService::PrepareForFirstSyncSetup() { // |PrepareForFirstSyncSetup| should always be called while the user is signed // out. At that time, sync setup is not completed. - DCHECK(!sync_service_->HasSyncSetupCompleted()); + DCHECK(!sync_service_->IsFirstSetupComplete()); sync_service_->SetSetupInProgress(true); } @@ -178,7 +178,7 @@ // Turn on the sync setup completed flag only if the user did not turn sync // off. if (sync_service_->CanSyncStart()) { - sync_service_->SetSyncSetupCompleted(); + sync_service_->SetFirstSetupComplete(); } }
diff --git a/ios/web/ios_web_shell.gyp b/ios/web/ios_web_shell.gyp index f076c296..135881d 100644 --- a/ios/web/ios_web_shell.gyp +++ b/ios/web/ios_web_shell.gyp
@@ -24,14 +24,6 @@ '-Xlinker -objc_abi_version -Xlinker 2' ] }, - # TODO(crbug.com/577748): Move mac_bundle_resources to ios_web_shell_lib. - 'mac_bundle_resources': [ - 'shell/Default.png', - 'shell/MainView.xib', - 'shell/textfield_background@2x.png', - 'shell/toolbar_back@2x.png', - 'shell/toolbar_forward@2x.png', - ], 'sources': [ 'shell/web_exe_main.mm', ], @@ -83,6 +75,13 @@ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework', '$(SDKROOT)/System/Library/Frameworks/UIKit.framework', ], + 'mac_bundle_resources': [ + 'shell/Default.png', + 'shell/MainView.xib', + 'shell/textfield_background@2x.png', + 'shell/toolbar_back@2x.png', + 'shell/toolbar_forward@2x.png', + ], }, }, ],
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index 0ad4ac0f..c170d8d 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc
@@ -404,6 +404,48 @@ return frame; } +// static +scoped_refptr<VideoFrame> VideoFrame::WrapExternalYuvaData( + VideoPixelFormat format, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, + int32_t y_stride, + int32_t u_stride, + int32_t v_stride, + int32_t a_stride, + uint8_t* y_data, + uint8_t* u_data, + uint8_t* v_data, + uint8_t* a_data, + base::TimeDelta timestamp) { + const StorageType storage = STORAGE_UNOWNED_MEMORY; + if (!IsValidConfig(format, storage, coded_size, visible_rect, natural_size)) { + LOG(DFATAL) << __FUNCTION__ << " Invalid config." + << ConfigToString(format, storage, coded_size, visible_rect, + natural_size); + return nullptr; + } + + if (NumPlanes(format) != 4) { + LOG(DFATAL) << "Expecting Y, U, V and A planes to be present for the video" + << " format."; + return nullptr; + } + + scoped_refptr<VideoFrame> frame(new VideoFrame( + format, storage, coded_size, visible_rect, natural_size, timestamp)); + frame->strides_[kYPlane] = y_stride; + frame->strides_[kUPlane] = u_stride; + frame->strides_[kVPlane] = v_stride; + frame->strides_[kAPlane] = a_stride; + frame->data_[kYPlane] = y_data; + frame->data_[kUPlane] = u_data; + frame->data_[kVPlane] = v_data; + frame->data_[kAPlane] = a_data; + return frame; +} + #if defined(OS_LINUX) // static scoped_refptr<VideoFrame> VideoFrame::WrapExternalDmabufs(
diff --git a/media/base/video_frame.h b/media/base/video_frame.h index ad7f4c0..22a2da6 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h
@@ -206,6 +206,23 @@ const gfx::GpuMemoryBufferHandle& v_handle, base::TimeDelta timestamp); + // Wraps external YUVA data of the given parameters with a VideoFrame. + // The returned VideoFrame does not own the data passed in. + static scoped_refptr<VideoFrame> WrapExternalYuvaData( + VideoPixelFormat format, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, + int32_t y_stride, + int32_t u_stride, + int32_t v_stride, + int32_t a_stride, + uint8_t* y_data, + uint8_t* u_data, + uint8_t* v_data, + uint8_t* a_data, + base::TimeDelta timestamp); + #if defined(OS_LINUX) // Wraps provided dmabufs // (https://www.kernel.org/doc/Documentation/dma-buf-sharing.txt) with a
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc index 9d27bc9..dff553ff 100644 --- a/media/filters/vpx_video_decoder.cc +++ b/media/filters/vpx_video_decoder.cc
@@ -136,19 +136,20 @@ int NumberOfFrameBuffersInUseByDecoder() const; int NumberOfFrameBuffersInUseByDecoderAndVideoFrame() const; - private: - friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>; - ~MemoryPool() override; - // Reference counted frame buffers used for VP9 decoding. Reference counting // is done manually because both chromium and libvpx has to release this // before a buffer can be re-used. struct VP9FrameBuffer { VP9FrameBuffer() : ref_cnt(0) {} std::vector<uint8_t> data; + std::vector<uint8_t> alpha_data; uint32_t ref_cnt; }; + private: + friend class base::RefCountedThreadSafe<VpxVideoDecoder::MemoryPool>; + ~MemoryPool() override; + // Gets the next available frame buffer for use by libvpx. VP9FrameBuffer* GetFreeFrameBuffer(size_t min_size); @@ -380,11 +381,11 @@ return false; // These are the combinations of codec-pixel format supported in principle. - // Note that VP9 does not support Alpha in the current implementation. DCHECK( (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12) || (config.codec() == kCodecVP8 && config.format() == PIXEL_FORMAT_YV12A) || (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12) || + (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV12A) || (config.codec() == kCodecVP9 && config.format() == PIXEL_FORMAT_YV24)); #if !defined(DISABLE_FFMPEG_VIDEO_DECODERS) @@ -400,9 +401,10 @@ if (!vpx_codec_) return false; - // Configure VP9 to decode on our buffers to skip a data copy on decoding. + // Configure VP9 to decode on our buffers to skip a data copy on + // decoding. For YV12A-VP9, we use our buffers for the Y, U and V planes and + // copy the A plane. if (config.codec() == kCodecVP9) { - DCHECK_NE(PIXEL_FORMAT_YV12A, config.format()); DCHECK(vpx_codec_get_caps(vpx_codec_->iface) & VPX_CODEC_CAP_EXTERNAL_FRAME_BUFFER); @@ -470,8 +472,26 @@ return false; } - if (!CopyVpxImageToVideoFrame(vpx_image, video_frame)) + const vpx_image_t* vpx_image_alpha = nullptr; + AlphaDecodeStatus alpha_decode_status = + DecodeAlphaPlane(vpx_image, &vpx_image_alpha, buffer); + if (alpha_decode_status == kAlphaPlaneError) { return false; + } else if (alpha_decode_status == kNoAlphaPlaneData) { + *video_frame = nullptr; + return true; + } + if (!CopyVpxImageToVideoFrame(vpx_image, vpx_image_alpha, video_frame)) { + return false; + } + if (vpx_image_alpha && config_.codec() == kCodecVP8) { + libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], + vpx_image_alpha->stride[VPX_PLANE_Y], + (*video_frame)->visible_data(VideoFrame::kAPlane), + (*video_frame)->stride(VideoFrame::kAPlane), + (*video_frame)->visible_rect().width(), + (*video_frame)->visible_rect().height()); + } (*video_frame)->set_timestamp(base::TimeDelta::FromMicroseconds(timestamp)); @@ -485,29 +505,26 @@ (*video_frame) ->metadata() ->SetInteger(VideoFrameMetadata::COLOR_SPACE, color_space); + return true; +} - if (!vpx_codec_alpha_) - return true; - - if (buffer->side_data_size() < 8) { - // TODO(mcasas): Is this a warning or an error? - DLOG(WARNING) << "Making Alpha channel opaque due to missing input"; - const uint32_t kAlphaOpaqueValue = 255; - libyuv::SetPlane((*video_frame)->visible_data(VideoFrame::kAPlane), - (*video_frame)->stride(VideoFrame::kAPlane), - (*video_frame)->visible_rect().width(), - (*video_frame)->visible_rect().height(), - kAlphaOpaqueValue); - return true; +VpxVideoDecoder::AlphaDecodeStatus VpxVideoDecoder::DecodeAlphaPlane( + const struct vpx_image* vpx_image, + const struct vpx_image** vpx_image_alpha, + const scoped_refptr<DecoderBuffer>& buffer) { + if (!vpx_codec_alpha_ || buffer->side_data_size() < 8) { + return kAlphaPlaneProcessed; } // First 8 bytes of side data is |side_data_id| in big endian. const uint64_t side_data_id = base::NetToHost64( *(reinterpret_cast<const uint64_t*>(buffer->side_data()))); - if (side_data_id != 1) - return true; + if (side_data_id != 1) { + return kAlphaPlaneProcessed; + } - // Try and decode buffer->side_data() minus the first 8 bytes as a full frame. + // Try and decode buffer->side_data() minus the first 8 bytes as a full + // frame. int64_t timestamp_alpha = buffer->timestamp().InMicroseconds(); void* user_priv_alpha = reinterpret_cast<void*>(×tamp_alpha); { @@ -519,48 +536,56 @@ if (status != VPX_CODEC_OK) { DLOG(ERROR) << "vpx_codec_decode() failed for the alpha: " << vpx_codec_error(vpx_codec_); - return false; + return kAlphaPlaneError; } } vpx_codec_iter_t iter_alpha = NULL; - const vpx_image_t* vpx_image_alpha = - vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); - if (!vpx_image_alpha) { - *video_frame = nullptr; - return true; + *vpx_image_alpha = vpx_codec_get_frame(vpx_codec_alpha_, &iter_alpha); + if (!(*vpx_image_alpha)) { + return kNoAlphaPlaneData; } - if (vpx_image_alpha->user_priv != user_priv_alpha) { + if ((*vpx_image_alpha)->user_priv != user_priv_alpha) { DLOG(ERROR) << "Invalid output timestamp on alpha."; - return false; + return kAlphaPlaneError; } - if (vpx_image_alpha->d_h != vpx_image->d_h || - vpx_image_alpha->d_w != vpx_image->d_w) { + if ((*vpx_image_alpha)->d_h != vpx_image->d_h || + (*vpx_image_alpha)->d_w != vpx_image->d_w) { DLOG(ERROR) << "The alpha plane dimensions are not the same as the " "image dimensions."; - return false; + return kAlphaPlaneError; } - libyuv::CopyPlane(vpx_image_alpha->planes[VPX_PLANE_Y], - vpx_image_alpha->stride[VPX_PLANE_Y], - (*video_frame)->visible_data(VideoFrame::kAPlane), - (*video_frame)->stride(VideoFrame::kAPlane), - (*video_frame)->visible_rect().width(), - (*video_frame)->visible_rect().height()); - return true; + if (config_.codec() == kCodecVP9) { + VpxVideoDecoder::MemoryPool::VP9FrameBuffer* frame_buffer = + static_cast<VpxVideoDecoder::MemoryPool::VP9FrameBuffer*>( + vpx_image->fb_priv); + uint64_t alpha_plane_size = + (*vpx_image_alpha)->stride[VPX_PLANE_Y] * (*vpx_image_alpha)->d_h; + if (frame_buffer->alpha_data.size() < alpha_plane_size) { + frame_buffer->alpha_data.resize(alpha_plane_size); + } + libyuv::CopyPlane((*vpx_image_alpha)->planes[VPX_PLANE_Y], + (*vpx_image_alpha)->stride[VPX_PLANE_Y], + &frame_buffer->alpha_data[0], + (*vpx_image_alpha)->stride[VPX_PLANE_Y], + (*vpx_image_alpha)->d_w, (*vpx_image_alpha)->d_h); + } + return kAlphaPlaneProcessed; } bool VpxVideoDecoder::CopyVpxImageToVideoFrame( const struct vpx_image* vpx_image, + const struct vpx_image* vpx_image_alpha, scoped_refptr<VideoFrame>* video_frame) { DCHECK(vpx_image); VideoPixelFormat codec_format; switch (vpx_image->fmt) { case VPX_IMG_FMT_I420: - codec_format = vpx_codec_alpha_ ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12; + codec_format = vpx_image_alpha ? PIXEL_FORMAT_YV12A : PIXEL_FORMAT_YV12; break; case VPX_IMG_FMT_I444: @@ -581,17 +606,25 @@ if (memory_pool_.get()) { DCHECK_EQ(kCodecVP9, config_.codec()); - DCHECK(!vpx_codec_alpha_) << "Uh-oh, VP9 and Alpha shouldn't coexist."; - *video_frame = VideoFrame::WrapExternalYuvData( - codec_format, - coded_size, gfx::Rect(visible_size), config_.natural_size(), - vpx_image->stride[VPX_PLANE_Y], - vpx_image->stride[VPX_PLANE_U], - vpx_image->stride[VPX_PLANE_V], - vpx_image->planes[VPX_PLANE_Y], - vpx_image->planes[VPX_PLANE_U], - vpx_image->planes[VPX_PLANE_V], - kNoTimestamp()); + if (vpx_image_alpha) { + VpxVideoDecoder::MemoryPool::VP9FrameBuffer* frame_buffer = + static_cast<VpxVideoDecoder::MemoryPool::VP9FrameBuffer*>( + vpx_image->fb_priv); + *video_frame = VideoFrame::WrapExternalYuvaData( + codec_format, coded_size, gfx::Rect(visible_size), + config_.natural_size(), vpx_image->stride[VPX_PLANE_Y], + vpx_image->stride[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_V], + vpx_image_alpha->stride[VPX_PLANE_Y], vpx_image->planes[VPX_PLANE_Y], + vpx_image->planes[VPX_PLANE_U], vpx_image->planes[VPX_PLANE_V], + &frame_buffer->alpha_data[0], kNoTimestamp()); + } else { + *video_frame = VideoFrame::WrapExternalYuvData( + codec_format, coded_size, gfx::Rect(visible_size), + config_.natural_size(), vpx_image->stride[VPX_PLANE_Y], + vpx_image->stride[VPX_PLANE_U], vpx_image->stride[VPX_PLANE_V], + vpx_image->planes[VPX_PLANE_Y], vpx_image->planes[VPX_PLANE_U], + vpx_image->planes[VPX_PLANE_V], kNoTimestamp()); + } if (!(*video_frame)) return false;
diff --git a/media/filters/vpx_video_decoder.h b/media/filters/vpx_video_decoder.h index c9000171..5423a88 100644 --- a/media/filters/vpx_video_decoder.h +++ b/media/filters/vpx_video_decoder.h
@@ -55,6 +55,14 @@ kError }; + // Return values for decoding alpha plane. + enum AlphaDecodeStatus { + kAlphaPlaneProcessed, // Alpha plane (if found) was decoded successfully. + kNoAlphaPlaneData, // Alpha plane was found, but decoder did not return any + // data. + kAlphaPlaneError // Fatal error occured when trying to decode alpha plane. + }; + // Handles (re-)initializing the decoder with a (new) config. // Returns true when initialization was successful. bool ConfigureDecoder(const VideoDecoderConfig& config); @@ -68,8 +76,14 @@ scoped_refptr<VideoFrame>* video_frame); bool CopyVpxImageToVideoFrame(const struct vpx_image* vpx_image, + const struct vpx_image* vpx_image_alpha, scoped_refptr<VideoFrame>* video_frame); + AlphaDecodeStatus DecodeAlphaPlane( + const struct vpx_image* vpx_image, + const struct vpx_image** vpx_image_alpha, + const scoped_refptr<DecoderBuffer>& buffer); + base::ThreadChecker thread_checker_; DecoderState state_;
diff --git a/media/test/data/bear-vp9a-odd-dimensions.webm b/media/test/data/bear-vp9a-odd-dimensions.webm new file mode 100644 index 0000000..d427f56 --- /dev/null +++ b/media/test/data/bear-vp9a-odd-dimensions.webm Binary files differ
diff --git a/media/test/data/bear-vp9a.webm b/media/test/data/bear-vp9a.webm new file mode 100644 index 0000000..f098687 --- /dev/null +++ b/media/test/data/bear-vp9a.webm Binary files differ
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc index 43da5c1d..2d00b5bf7 100644 --- a/media/test/pipeline_integration_test.cc +++ b/media/test/pipeline_integration_test.cc
@@ -1858,14 +1858,14 @@ // Verify that Opus audio in WebM containers can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_AudioOnly_Opus_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-opus-end-trimming.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-opus-end-trimming.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } // Verify that VP9 video in WebM containers can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VideoOnly_VP9_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-vp9.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } @@ -1873,14 +1873,14 @@ // Verify that VP9 video and Opus audio in the same WebM container can be played // back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Opus_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-opus.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-opus.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } // Verify that VP8 video with alpha channel can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV12A); @@ -1888,7 +1888,7 @@ // Verify that VP8A video with odd width/height can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP8A_Odd_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a-odd-dimensions.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp8a-odd-dimensions.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV12A); @@ -1896,11 +1896,27 @@ // Verify that VP9 video with odd width/height can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP9_Odd_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-odd-dimensions.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-odd-dimensions.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); } +// Verify that VP9 video with alpha channel can be played back. +TEST_F(PipelineIntegrationTest, BasicPlayback_VP9A_WebM) { + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9a.webm", kClockless)); + Play(); + ASSERT_TRUE(WaitUntilOnEnded()); + EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV12A); +} + +// Verify that VP9A video with odd width/height can be played back. +TEST_F(PipelineIntegrationTest, BasicPlayback_VP9A_Odd_WebM) { + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9a-odd-dimensions.webm", kClockless)); + Play(); + ASSERT_TRUE(WaitUntilOnEnded()); + EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV12A); +} + #if !defined(DISABLE_TEXT_TRACK_TESTS) // Verify that VP8 video with inband text track can be played back. TEST_F(PipelineIntegrationTest, BasicPlayback_VP8_WebVTT_WebM) { @@ -1913,7 +1929,7 @@ // Verify that VP9 video with 4:4:4 subsampling can be played back. TEST_F(PipelineIntegrationTest, P444_VP9_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-P444.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-320x240-P444.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV24); @@ -1922,7 +1938,7 @@ // Verify that frames of VP9 video in the BT.709 color space have the YV12HD // format. TEST_F(PipelineIntegrationTest, BT709_VP9_WebM) { - ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-bt709.webm")); + ASSERT_EQ(PIPELINE_OK, Start("bear-vp9-bt709.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); EXPECT_VIDEO_FORMAT_EQ(last_video_frame_format_, PIXEL_FORMAT_YV12); @@ -1931,7 +1947,7 @@ // Verify that videos with an odd frame size playback successfully. TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) { - ASSERT_EQ(PIPELINE_OK, Start("butterfly-853x480.webm")); + ASSERT_EQ(PIPELINE_OK, Start("butterfly-853x480.webm", kClockless)); Play(); ASSERT_TRUE(WaitUntilOnEnded()); }
diff --git a/net/filter/brotli_filter.cc b/net/filter/brotli_filter.cc index 939a6f7..91ff257 100644 --- a/net/filter/brotli_filter.cc +++ b/net/filter/brotli_filter.cc
@@ -6,6 +6,7 @@ #include "base/bit_cast.h" #include "base/macros.h" +#include "base/metrics/histogram_macros.h" #include "base/numerics/safe_conversions.h" #include "base/numerics/safe_math.h" #include "third_party/brotli/dec/decode.h" @@ -20,11 +21,39 @@ class BrotliFilter : public Filter { public: BrotliFilter(FilterType type) - : Filter(type), decoding_status_(DECODING_IN_PROGRESS) { - BrotliStateInit(&brotli_state_); + : Filter(type), + decoding_status_(DecodingStatus::DECODING_IN_PROGRESS), + used_memory_(0), + used_memory_maximum_(0), + consumed_bytes_(0), + produced_bytes_(0) { + brotli_state_ = BrotliCreateState(BrotliFilter::AllocateMemory, + BrotliFilter::FreeMemory, this); + CHECK(brotli_state_); } - ~BrotliFilter() override { BrotliStateCleanup(&brotli_state_); } + ~BrotliFilter() override { + BrotliDestroyState(brotli_state_); + brotli_state_ = nullptr; + DCHECK(used_memory_ == 0); + + UMA_HISTOGRAM_ENUMERATION( + "BrotliFilter.Status", static_cast<int>(decoding_status_), + static_cast<int>(DecodingStatus::DECODING_STATUS_COUNT)); + if (decoding_status_ == DecodingStatus::DECODING_DONE) { + UMA_HISTOGRAM_PERCENTAGE( + "BrotliFilter.CompressionPercent", + static_cast<int>((consumed_bytes_ * 100) / produced_bytes_)); + } + + // All code here is for gathering stats, and can be removed when + // BrotliFilter is considered stable. + static const int kBuckets = 48; + static const int64_t kMaxKb = 1 << (kBuckets / 3); // 64MiB in KiB + UMA_HISTOGRAM_CUSTOM_COUNTS("BrotliFilter.UsedMemoryKB", + used_memory_maximum_ / 1024, 1, kMaxKb, + kBuckets); + } // Decodes the pre-filter data and writes the output into the |dest_buffer| // passed in. @@ -42,12 +71,12 @@ if (!dest_buffer || !dest_len) return Filter::FILTER_ERROR; - if (decoding_status_ == DECODING_DONE) { + if (decoding_status_ == DecodingStatus::DECODING_DONE) { *dest_len = 0; return Filter::FILTER_DONE; } - if (decoding_status_ != DECODING_IN_PROGRESS) + if (decoding_status_ != DecodingStatus::DECODING_IN_PROGRESS) return Filter::FILTER_ERROR; size_t output_buffer_size = base::checked_cast<size_t>(*dest_len); @@ -60,10 +89,12 @@ size_t total_out = 0; BrotliResult result = BrotliDecompressStream(&available_in, &next_in, &available_out, - &next_out, &total_out, &brotli_state_); + &next_out, &total_out, brotli_state_); CHECK(available_in <= input_buffer_size); CHECK(available_out <= output_buffer_size); + consumed_bytes_ += input_buffer_size - available_in; + produced_bytes_ += output_buffer_size - available_out; base::CheckedNumeric<size_t> safe_bytes_written(output_buffer_size); safe_bytes_written -= available_out; @@ -78,7 +109,7 @@ stream_data_len_ = base::checked_cast<int>(available_in); next_stream_data_ = bit_cast<char*>(next_in); if (result == BROTLI_RESULT_SUCCESS) { - decoding_status_ = DECODING_DONE; + decoding_status_ = DecodingStatus::DECODING_DONE; return Filter::FILTER_DONE; } return Filter::FILTER_OK; @@ -90,19 +121,61 @@ return Filter::FILTER_NEED_MORE_DATA; default: - decoding_status_ = DECODING_ERROR; + decoding_status_ = DecodingStatus::DECODING_ERROR; return Filter::FILTER_ERROR; } } private: - enum DecodingStatus { DECODING_IN_PROGRESS, DECODING_DONE, DECODING_ERROR }; + static void* AllocateMemory(void* opaque, size_t size) { + BrotliFilter* filter = reinterpret_cast<BrotliFilter*>(opaque); + return filter->AllocateMemoryInternal(size); + } + + static void FreeMemory(void* opaque, void* address) { + BrotliFilter* filter = reinterpret_cast<BrotliFilter*>(opaque); + filter->FreeMemoryInternal(address); + } + + void* AllocateMemoryInternal(size_t size) { + size_t* array = reinterpret_cast<size_t*>(malloc(size + sizeof(size_t))); + if (!array) + return nullptr; + used_memory_ += size; + if (used_memory_maximum_ < used_memory_) + used_memory_maximum_ = used_memory_; + array[0] = size; + return &array[1]; + } + + void FreeMemoryInternal(void* address) { + if (!address) + return; + size_t* array = reinterpret_cast<size_t*>(address); + used_memory_ -= array[-1]; + free(&array[-1]); + } + + // Reported in UMA and must be kept in sync with the histograms.xml file. + enum class DecodingStatus : int { + DECODING_IN_PROGRESS = 0, + DECODING_DONE, + DECODING_ERROR, + + DECODING_STATUS_COUNT + // DECODING_STATUS_COUNT must always be the last element in this enum. + }; // Tracks the status of decoding. // This variable is updated only by ReadFilteredData. DecodingStatus decoding_status_; - BrotliState brotli_state_; + BrotliState* brotli_state_; + + size_t used_memory_; + size_t used_memory_maximum_; + size_t consumed_bytes_; + size_t produced_bytes_; DISALLOW_COPY_AND_ASSIGN(BrotliFilter); };
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h index 7b7350bb..8f0578a1 100644 --- a/net/log/net_log_event_type_list.h +++ b/net/log/net_log_event_type_list.h
@@ -1163,15 +1163,16 @@ // } EVENT_TYPE(HTTP2_SESSION_PUSHED_SYN_STREAM) -// This event is sent for sending an HTTP/2 (or SPDY) HEADERS frame. +// This event is sent for sending an HTTP/2 HEADERS frame. // The following parameters are attached: // { -// "flags": <The control frame flags>, // "headers": <The list of header:value pairs>, // "fin": <True if this is the final data set by the peer on this stream>, -// "unidirectional": <True if this stream is unidirectional>, -// "priority": <The priority value of the stream>, // "stream_id": <The stream id>, +// "has_priority": <True if the PRIORITY flag is set>, +// "parent_stream_id": <Optional; the stream id of the parent stream>, +// "priority": <Optional; the priority value of the stream>, +// "exclusive": <Optional; true if the exclusive bit is set>. // } EVENT_TYPE(HTTP2_SESSION_SEND_HEADERS)
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc index faa0459..b9d2af1 100644 --- a/net/spdy/spdy_session.cc +++ b/net/spdy/spdy_session.cc
@@ -98,6 +98,28 @@ return std::move(dict); } +scoped_ptr<base::Value> NetLogSpdyHeadersSentCallback( + const SpdyHeaderBlock* headers, + bool fin, + SpdyStreamId stream_id, + bool has_priority, + uint32_t priority, + SpdyStreamId parent_stream_id, + bool exclusive, + NetLogCaptureMode capture_mode) { + scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); + dict->Set("headers", SpdyHeaderBlockToListValue(*headers, capture_mode)); + dict->SetBoolean("fin", fin); + dict->SetInteger("stream_id", stream_id); + dict->SetBoolean("has_priority", has_priority); + if (has_priority) { + dict->SetInteger("parent_stream_id", parent_stream_id); + dict->SetInteger("priority", static_cast<int>(priority)); + dict->SetBoolean("exclusive", exclusive); + } + return std::move(dict); +} + scoped_ptr<base::Value> NetLogSpdySynStreamReceivedCallback( const SpdyHeaderBlock* headers, bool fin, @@ -1087,6 +1109,14 @@ syn_stream.set_unidirectional((flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0); syn_stream.set_header_block(block); syn_frame.reset(buffered_spdy_framer_->SerializeFrame(syn_stream)); + + if (net_log().IsCapturing()) { + net_log().AddEvent(NetLog::TYPE_HTTP2_SESSION_SYN_STREAM, + base::Bind(&NetLogSpdySynStreamSentCallback, &block, + (flags & CONTROL_FLAG_FIN) != 0, + (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0, + spdy_priority, stream_id)); + } } else { SpdyHeadersIR headers(stream_id); headers.set_priority(spdy_priority); @@ -1129,22 +1159,19 @@ headers.set_fin((flags & CONTROL_FLAG_FIN) != 0); headers.set_header_block(block); syn_frame.reset(buffered_spdy_framer_->SerializeFrame(headers)); + + if (net_log().IsCapturing()) { + net_log().AddEvent( + NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS, + base::Bind(&NetLogSpdyHeadersSentCallback, &block, + (flags & CONTROL_FLAG_FIN) != 0, stream_id, + headers.has_priority(), headers.priority(), + headers.parent_stream_id(), headers.exclusive())); + } } streams_initiated_count_++; - if (net_log().IsCapturing()) { - const NetLog::EventType type = - (GetProtocolVersion() <= SPDY3) - ? NetLog::TYPE_HTTP2_SESSION_SYN_STREAM - : NetLog::TYPE_HTTP2_SESSION_SEND_HEADERS; - net_log().AddEvent(type, - base::Bind(&NetLogSpdySynStreamSentCallback, &block, - (flags & CONTROL_FLAG_FIN) != 0, - (flags & CONTROL_FLAG_UNIDIRECTIONAL) != 0, - spdy_priority, stream_id)); - } - return syn_frame; }
diff --git a/remoting/protocol/connection_unittest.cc b/remoting/protocol/connection_unittest.cc index 12624356..9f35abd 100644 --- a/remoting/protocol/connection_unittest.cc +++ b/remoting/protocol/connection_unittest.cc
@@ -15,10 +15,13 @@ #include "remoting/protocol/ice_connection_to_host.h" #include "remoting/protocol/protocol_mock_objects.h" #include "remoting/protocol/transport_context.h" +#include "remoting/protocol/video_stream.h" #include "remoting/protocol/webrtc_connection_to_client.h" #include "remoting/protocol/webrtc_connection_to_host.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" using ::testing::_; using ::testing::InvokeWithoutArgs; @@ -57,6 +60,29 @@ const TransportRoute& route)); }; +class TestScreenCapturer : public webrtc::DesktopCapturer { + public: + TestScreenCapturer() {} + ~TestScreenCapturer() override {} + + // webrtc::DesktopCapturer interface. + void Start(Callback* callback) override { + callback_ = callback; + } + void Capture(const webrtc::DesktopRegion& region) override { + // Return black 10x10 frame. + scoped_ptr<webrtc::DesktopFrame> frame( + new webrtc::BasicDesktopFrame(webrtc::DesktopSize(100, 100))); + memset(frame->data(), 0, frame->stride() * frame->size().height()); + frame->mutable_updated_region()->SetRect( + webrtc::DesktopRect::MakeSize(frame->size())); + callback_->OnCaptureCompleted(frame.release()); + } + + private: + Callback* callback_ = nullptr; +}; + } // namespace class ConnectionTest : public testing::Test, @@ -65,14 +91,16 @@ ConnectionTest() {} protected: + bool is_using_webrtc() { return GetParam(); } + void SetUp() override { // Create fake sessions. host_session_ = new FakeSession(); owned_client_session_.reset(new FakeSession()); client_session_ = owned_client_session_.get(); - // Create Connection objects - if (GetParam()) { + // Create Connection objects. + if (is_using_webrtc()) { host_connection_.reset(new WebrtcConnectionToClient( make_scoped_ptr(host_session_), TransportContext::ForTests(protocol::TransportRole::SERVER))); @@ -248,5 +276,41 @@ run_loop.Run(); } +TEST_P(ConnectionTest, Video) { + Connect(); + + scoped_ptr<VideoStream> video_stream = host_connection_->StartVideoStream( + make_scoped_ptr(new TestScreenCapturer())); + + base::RunLoop run_loop; + + // Expect frames to be passed to FrameConsumer when WebRTC is used, or to + // VideoStub otherwise. + if (is_using_webrtc()) { + client_video_renderer_.GetFrameConsumer()->set_on_frame_callback( + base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop))); + } else { + client_video_renderer_.GetVideoStub()->set_on_frame_callback( + base::Bind(&base::RunLoop::Quit, base::Unretained(&run_loop))); + } + + run_loop.Run(); + + if (is_using_webrtc()) { + EXPECT_EQ( + client_video_renderer_.GetFrameConsumer()->received_frames().size(), + 1U); + EXPECT_EQ(client_video_renderer_.GetVideoStub()->received_packets().size(), + 0U); + } else { + EXPECT_EQ( + client_video_renderer_.GetFrameConsumer()->received_frames().size(), + 0U); + EXPECT_EQ(client_video_renderer_.GetVideoStub()->received_packets().size(), + 1U); + } + +} + } // namespace protocol } // namespace remoting
diff --git a/remoting/protocol/fake_video_renderer.cc b/remoting/protocol/fake_video_renderer.cc index faecf9b3..d30c4ad 100644 --- a/remoting/protocol/fake_video_renderer.cc +++ b/remoting/protocol/fake_video_renderer.cc
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/logging.h" #include "remoting/proto/video.pb.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" namespace remoting { namespace protocol { @@ -16,10 +17,48 @@ FakeVideoStub::FakeVideoStub() {} FakeVideoStub::~FakeVideoStub() {} +void FakeVideoStub::set_on_frame_callback(base::Closure on_frame_callback) { + CHECK(thread_checker_.CalledOnValidThread()); + on_frame_callback_ = on_frame_callback; +} + void FakeVideoStub::ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, const base::Closure& done) { + CHECK(thread_checker_.CalledOnValidThread()); received_packets_.push_back(std::move(video_packet)); - done.Run(); + if (!done.is_null()) + done.Run(); + if (!on_frame_callback_.is_null()) + on_frame_callback_.Run(); +} + +FakeFrameConsumer::FakeFrameConsumer() {} +FakeFrameConsumer::~FakeFrameConsumer() {} + +void FakeFrameConsumer::set_on_frame_callback(base::Closure on_frame_callback) { + CHECK(thread_checker_.CalledOnValidThread()); + on_frame_callback_ = on_frame_callback; +} + +scoped_ptr<webrtc::DesktopFrame> FakeFrameConsumer::AllocateFrame( + const webrtc::DesktopSize& size) { + CHECK(thread_checker_.CalledOnValidThread()); + return make_scoped_ptr(new webrtc::BasicDesktopFrame(size)); +} + +void FakeFrameConsumer::DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame, + const base::Closure& done) { + CHECK(thread_checker_.CalledOnValidThread()); + received_frames_.push_back(std::move(frame)); + if (!done.is_null()) + done.Run(); + if (!on_frame_callback_.is_null()) + on_frame_callback_.Run(); +} + +FrameConsumer::PixelFormat FakeFrameConsumer::GetPixelFormat() { + CHECK(thread_checker_.CalledOnValidThread()); + return FORMAT_BGRA; } FakeVideoRenderer::FakeVideoRenderer() {} @@ -28,12 +67,13 @@ void FakeVideoRenderer::OnSessionConfig(const SessionConfig& config) {} FakeVideoStub* FakeVideoRenderer::GetVideoStub() { + CHECK(thread_checker_.CalledOnValidThread()); return &video_stub_; } -FrameConsumer* FakeVideoRenderer::GetFrameConsumer() { - NOTIMPLEMENTED(); - return nullptr; +FakeFrameConsumer* FakeVideoRenderer::GetFrameConsumer() { + CHECK(thread_checker_.CalledOnValidThread()); + return &frame_consumer_; } } // namespace protocol
diff --git a/remoting/protocol/fake_video_renderer.h b/remoting/protocol/fake_video_renderer.h index a23f748..60a70888 100644 --- a/remoting/protocol/fake_video_renderer.h +++ b/remoting/protocol/fake_video_renderer.h
@@ -7,6 +7,10 @@ #include <list> +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" +#include "remoting/protocol/frame_consumer.h" #include "remoting/protocol/video_renderer.h" #include "remoting/protocol/video_stub.h" @@ -18,11 +22,45 @@ FakeVideoStub(); ~FakeVideoStub() override; + const std::list<scoped_ptr<VideoPacket>>& received_packets() { + return received_packets_; + } + + void set_on_frame_callback(base::Closure on_frame_callback); + // VideoStub interface. void ProcessVideoPacket(scoped_ptr<VideoPacket> video_packet, const base::Closure& done) override; private: + base::ThreadChecker thread_checker_; + std::list<scoped_ptr<VideoPacket>> received_packets_; + base::Closure on_frame_callback_; +}; + +class FakeFrameConsumer : public FrameConsumer { + public: + FakeFrameConsumer(); + ~FakeFrameConsumer() override; + + const std::list<scoped_ptr<webrtc::DesktopFrame>>& received_frames() { + return received_frames_; + } + + void set_on_frame_callback(base::Closure on_frame_callback); + + // FrameConsumer interface. + scoped_ptr<webrtc::DesktopFrame> AllocateFrame( + const webrtc::DesktopSize& size) override; + void DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame, + const base::Closure& done) override; + PixelFormat GetPixelFormat() override; + + private: + base::ThreadChecker thread_checker_; + + std::list<scoped_ptr<webrtc::DesktopFrame>> received_frames_; + base::Closure on_frame_callback_; }; class FakeVideoRenderer : public VideoRenderer { @@ -33,10 +71,13 @@ // VideoRenderer interface. void OnSessionConfig(const SessionConfig& config) override; FakeVideoStub* GetVideoStub() override; - FrameConsumer* GetFrameConsumer() override; + FakeFrameConsumer* GetFrameConsumer() override; private: + base::ThreadChecker thread_checker_; + FakeVideoStub video_stub_; + FakeFrameConsumer frame_consumer_; }; } // namespace protocol
diff --git a/remoting/protocol/frame_consumer.h b/remoting/protocol/frame_consumer.h index 87c8ca20..7dde4fc8 100644 --- a/remoting/protocol/frame_consumer.h +++ b/remoting/protocol/frame_consumer.h
@@ -5,7 +5,9 @@ #ifndef REMOTING_PROTOCOL_FRAME_CONSUMER_H_ #define REMOTING_PROTOCOL_FRAME_CONSUMER_H_ +#include "base/callback_forward.h" #include "base/macros.h" +#include "base/memory/scoped_ptr.h" namespace webrtc { class DesktopFrame;
diff --git a/remoting/protocol/webrtc_connection_to_client.cc b/remoting/protocol/webrtc_connection_to_client.cc index 1fbbad11..1c23e2d 100644 --- a/remoting/protocol/webrtc_connection_to_client.cc +++ b/remoting/protocol/webrtc_connection_to_client.cc
@@ -157,6 +157,14 @@ Disconnect(error); } +void WebrtcConnectionToClient::OnWebrtcTransportMediaStreamAdded( + scoped_refptr<webrtc::MediaStreamInterface> stream) { + LOG(WARNING) << "The client created an unexpected media stream."; +} + +void WebrtcConnectionToClient::OnWebrtcTransportMediaStreamRemoved( + scoped_refptr<webrtc::MediaStreamInterface> stream) {} + void WebrtcConnectionToClient::OnChannelInitialized( ChannelDispatcherBase* channel_dispatcher) { DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/remoting/protocol/webrtc_connection_to_client.h b/remoting/protocol/webrtc_connection_to_client.h index 1786374..06fadd67 100644 --- a/remoting/protocol/webrtc_connection_to_client.h +++ b/remoting/protocol/webrtc_connection_to_client.h
@@ -54,6 +54,10 @@ void OnWebrtcTransportConnecting() override; void OnWebrtcTransportConnected() override; void OnWebrtcTransportError(ErrorCode error) override; + void OnWebrtcTransportMediaStreamAdded( + scoped_refptr<webrtc::MediaStreamInterface> stream) override; + void OnWebrtcTransportMediaStreamRemoved( + scoped_refptr<webrtc::MediaStreamInterface> stream) override; // ChannelDispatcherBase::EventHandler interface. void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) override;
diff --git a/remoting/protocol/webrtc_connection_to_host.cc b/remoting/protocol/webrtc_connection_to_host.cc index 9733163a..351bb8d3 100644 --- a/remoting/protocol/webrtc_connection_to_host.cc +++ b/remoting/protocol/webrtc_connection_to_host.cc
@@ -12,7 +12,9 @@ #include "remoting/protocol/client_stub.h" #include "remoting/protocol/clipboard_stub.h" #include "remoting/protocol/transport_context.h" +#include "remoting/protocol/video_renderer.h" #include "remoting/protocol/webrtc_transport.h" +#include "remoting/protocol/webrtc_video_renderer_adapter.h" namespace remoting { namespace protocol { @@ -64,7 +66,7 @@ } void WebrtcConnectionToHost::set_video_renderer(VideoRenderer* video_renderer) { - NOTIMPLEMENTED(); + video_renderer_ = video_renderer; } void WebrtcConnectionToHost::set_audio_stub(AudioStub* audio_stub) { @@ -88,9 +90,13 @@ break; case Session::CLOSED: + CloseChannels(); + SetState(CLOSED, OK); + break; + case Session::FAILED: CloseChannels(); - SetState(CLOSED, state == Session::FAILED ? session_->error() : OK); + SetState(FAILED, session_->error()); break; } } @@ -112,6 +118,22 @@ SetState(FAILED, error); } +void WebrtcConnectionToHost::OnWebrtcTransportMediaStreamAdded( + scoped_refptr<webrtc::MediaStreamInterface> stream) { + if (video_adapter_) { + LOG(WARNING) + << "Received multiple media streams. Ignoring all except the last one."; + } + video_adapter_.reset(new WebrtcVideoRendererAdapter( + stream, video_renderer_->GetFrameConsumer())); +} + +void WebrtcConnectionToHost::OnWebrtcTransportMediaStreamRemoved( + scoped_refptr<webrtc::MediaStreamInterface> stream) { + if (video_adapter_ && video_adapter_->label() == stream->label()) + video_adapter_.reset(); +} + void WebrtcConnectionToHost::OnChannelInitialized( ChannelDispatcherBase* channel_dispatcher) { NotifyIfChannelsReady();
diff --git a/remoting/protocol/webrtc_connection_to_host.h b/remoting/protocol/webrtc_connection_to_host.h index 030adcc..755e4ce9 100644 --- a/remoting/protocol/webrtc_connection_to_host.h +++ b/remoting/protocol/webrtc_connection_to_host.h
@@ -23,6 +23,7 @@ class ClientControlDispatcher; class ClientEventDispatcher; class SessionConfig; +class WebrtcVideoRendererAdapter; class WebrtcConnectionToHost : public ConnectionToHost, public Session::EventHandler, @@ -54,6 +55,10 @@ void OnWebrtcTransportConnecting() override; void OnWebrtcTransportConnected() override; void OnWebrtcTransportError(ErrorCode error) override; + void OnWebrtcTransportMediaStreamAdded( + scoped_refptr<webrtc::MediaStreamInterface> stream) override; + void OnWebrtcTransportMediaStreamRemoved( + scoped_refptr<webrtc::MediaStreamInterface> stream) override; // ChannelDispatcherBase::EventHandler interface. void OnChannelInitialized(ChannelDispatcherBase* channel_dispatcher) override; @@ -70,6 +75,7 @@ // Stub for incoming messages. ClientStub* client_stub_ = nullptr; + VideoRenderer* video_renderer_ = nullptr; ClipboardStub* clipboard_stub_ = nullptr; scoped_ptr<Session> session_; @@ -80,6 +86,8 @@ ClipboardFilter clipboard_forwarder_; InputFilter event_forwarder_; + scoped_ptr<WebrtcVideoRendererAdapter> video_adapter_; + // Internal state of the connection. State state_ = INITIALIZING; ErrorCode error_ = OK;
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc index cf3235e..76336cc 100644 --- a/remoting/protocol/webrtc_transport.cc +++ b/remoting/protocol/webrtc_transport.cc
@@ -348,12 +348,12 @@ void WebrtcTransport::OnAddStream(webrtc::MediaStreamInterface* stream) { DCHECK(thread_checker_.CalledOnValidThread()); - LOG(ERROR) << "Stream added " << stream->label(); + event_handler_->OnWebrtcTransportMediaStreamAdded(stream); } void WebrtcTransport::OnRemoveStream(webrtc::MediaStreamInterface* stream) { DCHECK(thread_checker_.CalledOnValidThread()); - LOG(ERROR) << "Stream removed " << stream->label(); + event_handler_->OnWebrtcTransportMediaStreamRemoved(stream); } void WebrtcTransport::OnDataChannel(
diff --git a/remoting/protocol/webrtc_transport.h b/remoting/protocol/webrtc_transport.h index a54be6e..8a7f43bd 100644 --- a/remoting/protocol/webrtc_transport.h +++ b/remoting/protocol/webrtc_transport.h
@@ -45,6 +45,12 @@ // Called when there is an error connecting the session. virtual void OnWebrtcTransportError(ErrorCode error) = 0; + + // Called when an incoming media stream is added or removed. + virtual void OnWebrtcTransportMediaStreamAdded( + scoped_refptr<webrtc::MediaStreamInterface> stream) = 0; + virtual void OnWebrtcTransportMediaStreamRemoved( + scoped_refptr<webrtc::MediaStreamInterface> stream) = 0; }; WebrtcTransport(rtc::Thread* worker_thread, @@ -125,9 +131,6 @@ ScopedVector<webrtc::IceCandidateInterface> pending_incoming_candidates_; - std::list<rtc::scoped_refptr<webrtc::MediaStreamInterface>> - unclaimed_streams_; - WebrtcDataStreamAdapter outgoing_data_stream_adapter_; WebrtcDataStreamAdapter incoming_data_stream_adapter_;
diff --git a/remoting/protocol/webrtc_transport_unittest.cc b/remoting/protocol/webrtc_transport_unittest.cc index 737f2914f..b4e3ec60 100644 --- a/remoting/protocol/webrtc_transport_unittest.cc +++ b/remoting/protocol/webrtc_transport_unittest.cc
@@ -60,6 +60,10 @@ void OnWebrtcTransportError(ErrorCode error) override { error_callback_.Run(error); } + void OnWebrtcTransportMediaStreamAdded( + scoped_refptr<webrtc::MediaStreamInterface> stream) override {} + void OnWebrtcTransportMediaStreamRemoved( + scoped_refptr<webrtc::MediaStreamInterface> stream) override {} private: base::Closure connecting_callback_;
diff --git a/remoting/protocol/webrtc_video_renderer_adapter.cc b/remoting/protocol/webrtc_video_renderer_adapter.cc new file mode 100644 index 0000000..757074e --- /dev/null +++ b/remoting/protocol/webrtc_video_renderer_adapter.cc
@@ -0,0 +1,79 @@ +// 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 "remoting/protocol/webrtc_video_renderer_adapter.h" + +#include <utility> + +#include "base/bind.h" +#include "base/callback.h" +#include "base/location.h" +#include "base/memory/scoped_ptr.h" +#include "base/single_thread_task_runner.h" +#include "base/thread_task_runner_handle.h" +#include "remoting/protocol/frame_consumer.h" +#include "third_party/libjingle/source/talk/media/base/videoframe.h" +#include "third_party/libyuv/include/libyuv/video_common.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" + +namespace remoting { +namespace protocol { + +WebrtcVideoRendererAdapter::WebrtcVideoRendererAdapter( + scoped_refptr<webrtc::MediaStreamInterface> media_stream, + FrameConsumer* frame_consumer) + : media_stream_(std::move(media_stream)), + frame_consumer_(frame_consumer), + output_format_fourcc_(frame_consumer_->GetPixelFormat() == + FrameConsumer::FORMAT_BGRA + ? libyuv::FOURCC_ARGB + : libyuv::FOURCC_ABGR), + task_runner_(base::ThreadTaskRunnerHandle::Get()), + weak_factory_(this) { + webrtc::VideoTrackVector video_tracks = media_stream_->GetVideoTracks(); + if (video_tracks.empty()) { + LOG(ERROR) << "Received media stream with no video tracks."; + return; + } + + if (video_tracks.size() > 1U) { + LOG(WARNING) << "Received media stream with multiple video tracks."; + } + + video_tracks[0]->AddRenderer(this); +} + +WebrtcVideoRendererAdapter::~WebrtcVideoRendererAdapter() { + DCHECK(task_runner_->BelongsToCurrentThread()); +} + +void WebrtcVideoRendererAdapter::RenderFrame(const cricket::VideoFrame* frame) { + // TODO(sergeyu): WebRTC calls RenderFrame on a separate thread it creates. + // FrameConsumer normally expects to be called on the network thread, so we + // cannot call FrameConsumer::AllocateFrame() here and instead + // BasicDesktopFrame is created directly. This will not work correctly with + // all FrameConsumer implementations. Fix this somehow. + scoped_ptr<webrtc::DesktopFrame> rgb_frame(new webrtc::BasicDesktopFrame( + webrtc::DesktopSize(frame->GetWidth(), frame->GetHeight()))); + + frame->ConvertToRgbBuffer( + output_format_fourcc_, rgb_frame->data(), + std::abs(rgb_frame->stride()) * rgb_frame->size().height(), + rgb_frame->stride()); + rgb_frame->mutable_updated_region()->AddRect( + webrtc::DesktopRect::MakeSize(rgb_frame->size())); + task_runner_->PostTask( + FROM_HERE, + base::Bind(&WebrtcVideoRendererAdapter::DrawFrame, + weak_factory_.GetWeakPtr(), base::Passed(&rgb_frame))); +} + +void WebrtcVideoRendererAdapter::DrawFrame( + scoped_ptr<webrtc::DesktopFrame> frame) { + DCHECK(task_runner_->BelongsToCurrentThread()); + frame_consumer_->DrawFrame(std::move(frame), base::Closure()); +} + +} // namespace remoting +} // namespace protocol
diff --git a/remoting/protocol/webrtc_video_renderer_adapter.h b/remoting/protocol/webrtc_video_renderer_adapter.h new file mode 100644 index 0000000..87efcc97 --- /dev/null +++ b/remoting/protocol/webrtc_video_renderer_adapter.h
@@ -0,0 +1,53 @@ +// 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. + +#ifndef REMOTING_PROTOCOL_WEBRTC_VIDEO_RENDERER_ADAPTER_H_ +#define REMOTING_PROTOCOL_WEBRTC_VIDEO_RENDERER_ADAPTER_H_ + +#include "base/memory/ref_counted.h" +#include "base/memory/weak_ptr.h" +#include "third_party/libjingle/source/talk/app/webrtc/mediastreaminterface.h" + +namespace base { +class SingleThreadTaskRunner; +} // namespace base + +namespace webrtc { +class DesktopFrame; +} // namespace webrtc + +namespace remoting { +namespace protocol { + +class FrameConsumer; + +class WebrtcVideoRendererAdapter : public webrtc::VideoRendererInterface { + public: + WebrtcVideoRendererAdapter( + scoped_refptr<webrtc::MediaStreamInterface> media_stream, + FrameConsumer* frame_consumer); + ~WebrtcVideoRendererAdapter() override; + + std::string label() const { return media_stream_->label(); } + + // webrtc::VideoRendererInterface implementation. + void RenderFrame(const cricket::VideoFrame* frame) override; + + private: + void DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame); + + scoped_refptr<webrtc::MediaStreamInterface> media_stream_; + FrameConsumer* frame_consumer_; + uint32_t output_format_fourcc_; + scoped_refptr<base::SingleThreadTaskRunner> task_runner_; + + base::WeakPtrFactory<WebrtcVideoRendererAdapter> weak_factory_; + + DISALLOW_COPY_AND_ASSIGN(WebrtcVideoRendererAdapter); +}; + +} // namespace remoting +} // namespace protocol + +#endif // REMOTING_PROTOCOL_WEBRTC_VIDEO_RENDERER_ADAPTER_H_
diff --git a/remoting/remoting_srcs.gypi b/remoting/remoting_srcs.gypi index 8f16e55..5c2db03e 100644 --- a/remoting/remoting_srcs.gypi +++ b/remoting/remoting_srcs.gypi
@@ -228,6 +228,8 @@ 'protocol/webrtc_video_capturer_adapter.h', 'protocol/webrtc_video_stream.cc', 'protocol/webrtc_video_stream.h', + 'protocol/webrtc_video_renderer_adapter.cc', + 'protocol/webrtc_video_renderer_adapter.h', ], 'remoting_signaling_sources': [
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h index 741f73d..938b45f 100644 --- a/skia/config/SkUserConfig.h +++ b/skia/config/SkUserConfig.h
@@ -206,6 +206,10 @@ // // Remove these as we update our sites. // +#ifndef SK_SUPPORT_LEGACY_CONIC_MEASURE +# define SK_SUPPORT_LEGACY_CONIC_MEASURE +#endif + #ifndef SK_SUPPORT_LEGACY_GETTOPDEVICE # define SK_SUPPORT_LEGACY_GETTOPDEVICE #endif
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index af9de86..4780645 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -128,8 +128,7 @@ crbug.com/520612 [ Linux ] fullscreen/anonymous-block-merge-crash.html [ Pass Timeout ] crbug.com/520613 http/tests/cache/freshness-header.html [ Failure Pass ] crbug.com/520614 http/tests/w3c/webperf/submission/Intel/resource-timing/test_resource_timing_buffer_size_restriction.html [ Failure Pass ] -# Next line is commented out to allow rebaseline for crbug.com/576728 below -#crbug.com/520619 [ Android Mac Linux XP Win7 ] webexposed/global-interface-listing.html [ Pass Timeout ] +crbug.com/520619 [ Android Mac Linux XP Win7 ] webexposed/global-interface-listing.html [ Pass Timeout ] crbug.com/520194 http/tests/xmlhttprequest/timeout/xmlhttprequest-timeout-worker-overridesexpires.html [ Failure Pass ] crbug.com/520199 [ Mac ] plugins/plugin-initiate-popup-window.html [ Failure Pass ] crbug.com/518967 [ Win7 ] http/tests/htmlimports/csp-import-block-but-nonce-nested.html [ Failure Pass Timeout ] @@ -159,9 +158,6 @@ crbug.com/518995 media/track/media-element-move-to-new-document-assert.html [ Failure Pass ] crbug.com/518998 media/video-poster-after-loadedmetadata.html [ Failure Pass ] -crbug.com/527579 fast/replaced/border-radius-clip.html [ NeedsRebaseline ] -crbug.com/527579 http/tests/media/video-buffered-range-contains-currentTime.html [ NeedsRebaseline ] - # These performance-sensitive user-timing tests are flaky in debug on all platforms, and flaky on all configurations of windows. # See: crbug.com/567965, crbug.com/518992, and crbug.com/518993 crbug.com/567965 [ Debug ] imported/web-platform-tests/user-timing/test_user_timing_measure.html [ Skip ] @@ -254,6 +250,9 @@ crbug.com/576589 fast/repaint/multi-layout-one-frame.html [ NeedsRebaseline ] crbug.com/576589 fast/repaint/subtree-root-skipped.html [ NeedsRebaseline ] crbug.com/576589 fast/text/international/mixed-directionality-selection.html [ NeedsRebaseline ] +crbug.com/576589 [ Mac10.10 ] tables/mozilla/bugs/bug46368-1.html [ NeedsRebaseline ] +crbug.com/576589 [ Mac10.10 ] tables/mozilla/bugs/bug46368-2.html [ NeedsRebaseline ] +crbug.com/576589 [ Mac10.10 ] tables/mozilla/dom/tableDom.html [ NeedsRebaseline ] crbug.com/498539 http/tests/inspector/elements/styles/selector-line.html [ Pass Timeout ] crbug.com/498539 http/tests/inspector/network/network-datareceived.html [ Pass Timeout ] @@ -913,17 +912,6 @@ crbug.com/471824 virtual/pointerevent/imported/web-platform-tests/pointerevents/pointerevent_touch-action-illegal.html [ Skip ] crbug.com/471824 virtual/pointerevent/imported/web-platform-tests/pointerevents/pointerevent_touch-action-verification.html [ Skip ] -# Proxy and Reflect -crbug.com/576728 virtual/stable/http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ NeedsManualRebaseline ] -crbug.com/576728 http/tests/serviceworker/webexposed/global-interface-listing-service-worker.html [ NeedsManualRebaseline ] -crbug.com/576728 webexposed/global-interface-listing.html [ NeedsManualRebaseline ] -crbug.com/576728 webexposed/global-interface-listing-compositor-worker.html [ NeedsManualRebaseline ] -crbug.com/576728 webexposed/global-interface-listing-dedicated-worker.html [ NeedsManualRebaseline ] -crbug.com/576728 virtual/stable/webexposed/global-interface-listing.html [ NeedsManualRebaseline ] -crbug.com/576728 webexposed/global-interface-listing-shared-worker.html [ NeedsManualRebaseline ] -crbug.com/576728 virtual/stable/webexposed/global-interface-listing-shared-worker.html [ NeedsManualRebaseline ] -crbug.com/576728 virtual/stable/webexposed/global-interface-listing-dedicated-worker.html [ NeedsManualRebaseline ] - # Not implemented yet crbug.com/336604 imported/csswg-test/css-flexbox-1/flexbox_visibility-collapse-line-wrapping.html [ Failure ] crbug.com/336604 imported/csswg-test/css-flexbox-1/flexbox_visibility-collapse.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers-expected.txt b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers-expected.txt index 9336a8a..1a07f4ad 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers-expected.txt
@@ -1,10 +1,10 @@ -[Worker] Test createImageBitmap with blob in workers. +Test createImageBitmap with blob in workers. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". Starting worker: ./resources/canvas-createImageBitmap-blob-in-workers.js -PASS [Worker] Promise fulfuilled. +PASS ImageBitmaps created from blob in worker and in main have the same pixel data PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers.html b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers.html index 8486727..ea845ef2 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers.html +++ b/third_party/WebKit/LayoutTests/fast/canvas/canvas-createImageBitmap-blob-in-workers.html
@@ -5,15 +5,74 @@ </head> <body> <script> +jsTestIsAsync = true; var worker = startWorker('./resources/canvas-createImageBitmap-blob-in-workers.js'); -var xhr = new XMLHttpRequest(); -xhr.open("GET", 'resources/pattern.png'); -xhr.responseType = 'blob'; -xhr.send(); -xhr.onload = function() { - worker.postMessage(xhr.response); +description('Test createImageBitmap with blob in workers.'); + +var imgWidth = 20; +var imgHeight = 20; +var imageData2; +var numOfBitmaps = 5; +var bitmapArray = []; + +var canvas1 = document.createElement("canvas"); +var ctx1 = canvas1.getContext("2d"); +ctx1.fillStyle = "#FF0000"; +ctx1.fillRect(0, 0, imgWidth, imgHeight); + +function compareImageData(data1, data2) +{ + if (data1.length != data2.length) { + testFailed("The two image have different dimensions"); + finishJSTest(); + } + for (var i = 0; i < data1.length; i++) { + if (data1[i] != data2[i]) { + testFailed("The two image have different pixel data"); + finishJSTest(); + } + } } + +var newImg = new Image(); +newImg.onload = function() { + var canvas2 = document.createElement("canvas"); + var ctx2 = canvas2.getContext("2d"); + ctx2.drawImage(newImg, 0, 0, imgWidth, imgHeight); + imageData2 = ctx2.getImageData(0, 0, imgWidth, imgHeight).data; + + var canvas3 = document.createElement("canvas"); + var ctx3 = canvas3.getContext("2d"); + for (var i = 0; i < numOfBitmaps; i++) { + ctx3.clearRect(0, 0, imgWidth, imgHeight); + ctx3.drawImage(bitmapArray[i], 0, 0, imgWidth, imgHeight); + var imageData = ctx3.getImageData(0, 0, imgWidth, imgHeight).data; + compareImageData(imageData, imageData2); + } + + worker.onmessage = function(e) { + var newImageBitmap = e.data.data; + ctx3.clearRect(0, 0, imgWidth, imgHeight); + ctx3.drawImage(newImageBitmap, 0, 0, imgWidth, imgHeight); + var imageData = ctx3.getImageData(0, 0, imgWidth, imgHeight).data; + compareImageData(imageData, imageData2); + testPassed("ImageBitmaps created from blob in worker and in main have the same pixel data"); + finishJSTest(); + } +} + +canvas1.toBlob(function(blob) { + worker.postMessage(blob); + for (var i = 0; i < numOfBitmaps; i++) { + createImageBitmap(blob).then(imageBitmap => { + bitmapArray.push(imageBitmap); + }); + } + url = URL.createObjectURL(blob); + newImg.src = url; +}); + </script> </body> -</html> \ No newline at end of file +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-createImageBitmap-blob-in-workers.js b/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-createImageBitmap-blob-in-workers.js index 07b5a4a3..1f71802d 100644 --- a/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-createImageBitmap-blob-in-workers.js +++ b/third_party/WebKit/LayoutTests/fast/canvas/resources/canvas-createImageBitmap-blob-in-workers.js
@@ -1,15 +1,5 @@ -importScripts('../../../resources/js-test.js'); - -self.jsTestIsAsync = true; - -description('Test createImageBitmap with blob in workers.'); - self.addEventListener('message', function(e) { - createImageBitmap(e.data).then(function() { - testPassed('Promise fulfuilled.'); - finishJSTest(); - }, function() { - testFailed('Promise rejected.'); - finishJSTest(); + createImageBitmap(e.data).then(imageBitmap => { + postMessage({data: imageBitmap}, [imageBitmap]); }); -}); \ No newline at end of file +});
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid-expected.txt index 5807b83..6449d1c 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid-expected.txt
@@ -1,4 +1,19 @@ This test checks the behavior of the absolutely positioned grid items placed on the implicit grid. -PASS +TODO(rego): width and height of 1st and 3rd items in the next grid should be 230px once we solve http://crbug.com/562167 + +FAIL: +Expected 230 for width, but got 215. +Expected 230 for height, but got 215. +Expected 230 for width, but got 215. +Expected 230 for height, but got 215. + +<div class="grid"> + <div class="sizedToGridArea absolute secondRowSecondColumn" data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> + </div> + <div class="sizedToGridArea absolute endSecondRowEndSecondColumn" data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> + </div> + <div class="sizedToGridArea absolute onlySecondRowOnlySecondColumn" data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> + </div> +</div> PASS
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid.html index 143d7ede3..29fd80b9 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-implicit-grid.html
@@ -28,6 +28,8 @@ <p>This test checks the behavior of the absolutely positioned grid items placed on the implicit grid.</p> +<p>TODO(rego): width and height of 1st and 3rd items in the next grid should be 230px once we solve http://crbug.com/562167</p> + <div class="grid"> <div class="sizedToGridArea absolute secondRowSecondColumn" data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> @@ -42,13 +44,13 @@ <div class="grid grid-columns-rows"> <div class="sizedToGridArea absolute secondRowSecondColumn" - data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> + data-offset-x="115" data-offset-y="65" data-expected-width="115" data-expected-height="165"> </div> <div class="sizedToGridArea absolute endSecondRowEndSecondColumn" data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> </div> <div class="sizedToGridArea absolute onlySecondRowOnlySecondColumn" - data-offset-x="15" data-offset-y="15" data-expected-width="230" data-expected-height="230"> + data-offset-x="115" data-offset-y="65" data-expected-width="115" data-expected-height="165"> </div> </div>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-padding.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-padding.html new file mode 100644 index 0000000..c2601d3 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-padding.html
@@ -0,0 +1,119 @@ +<!DOCTYPE html> +<link href="resources/grid.css" rel="stylesheet"> +<style> + +.grid { + grid-template-columns: 100px 200px; + grid-template-rows: 50px 150px; + width: 500px; + height: 300px; + border: 5px solid black; + margin: 30px; + padding: 15px; + /* Ensures that the grid container is the containing block of the absolutely positioned grid children. */ + position: relative; +} + +.absolute { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: lime; +} + +</style> +<script src="../../resources/testharness.js"></script> +<script src="../../resources/testharnessreport.js"></script> +<script src="../../resources/check-layout-th.js"></script> +<body onload="checkLayout('.grid')"> +<div id="log"></div> + +<p>This test checks that positioned grid items can be placed directly on the padding.</p> + +<div class="grid"> + <div class="absolute" style="grid-column: auto / 1; grid-row: auto / 1;" + data-offset-x="0" data-offset-y="0" data-expected-width="15" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: 1 / 2; grid-row: auto / 1;" + data-offset-x="15" data-offset-y="0" data-expected-width="100" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: auto / 1; grid-row: 1 / 2;" + data-offset-x="0" data-offset-y="15" data-expected-width="15" data-expected-height="50"> + </div> + <div class="absolute" style="grid-column: 3 / auto; grid-row: 3 / auto;" + data-offset-x="315" data-offset-y="215" data-expected-width="215" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 2 / 3; grid-row: 3 / auto;" + data-offset-x="115" data-offset-y="215" data-expected-width="200" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 3 / auto; grid-row: 2 / 3;" + data-offset-x="315" data-offset-y="65" data-expected-width="215" data-expected-height="150"> + </div> +</div> + +<div class="grid"> + <div class="absolute" style="grid-column: -5 / 1; grid-row: -5 / 1;" + data-offset-x="0" data-offset-y="0" data-expected-width="15" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: 1 / 2; grid-row: -5 / 1;" + data-offset-x="15" data-offset-y="0" data-expected-width="100" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: -5 / 1; grid-row: 1 / 2;" + data-offset-x="0" data-offset-y="15" data-expected-width="15" data-expected-height="50"> + </div> + <div class="absolute" style="grid-column: 3 / 5; grid-row: 3 / 5;" + data-offset-x="315" data-offset-y="215" data-expected-width="215" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 2 / 3; grid-row: 3 / 5;" + data-offset-x="115" data-offset-y="215" data-expected-width="200" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 3 / 5; grid-row: 2 / 3;" + data-offset-x="315" data-offset-y="65" data-expected-width="215" data-expected-height="150"> + </div> +</div> + +<div class="grid"> + <div class="absolute" style="grid-column: span 2 / 1; grid-row: span 2 / 1;" + data-offset-x="0" data-offset-y="0" data-expected-width="15" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: 1 / 2; grid-row: span 2 / 1;" + data-offset-x="15" data-offset-y="0" data-expected-width="100" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: span 2 / 1; grid-row: 1 / 2;" + data-offset-x="0" data-offset-y="15" data-expected-width="15" data-expected-height="50"> + </div> + <div class="absolute" style="grid-column: 3 / span 2; grid-row: 3 / span 2;" + data-offset-x="315" data-offset-y="215" data-expected-width="215" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 2 / 3; grid-row: 3 / span 2;" + data-offset-x="115" data-offset-y="215" data-expected-width="200" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 3 / span 2; grid-row: 2 / 3;" + data-offset-x="315" data-offset-y="65" data-expected-width="215" data-expected-height="150"> + </div> +</div> + +<div class="grid"> + <div class="absolute" style="grid-column: foo / 1; grid-row: foo / 1;" + data-offset-x="0" data-offset-y="0" data-expected-width="15" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: 1 / 2; grid-row: foo / 1;" + data-offset-x="15" data-offset-y="0" data-expected-width="100" data-expected-height="15"> + </div> + <div class="absolute" style="grid-column: foo / 1; grid-row: 1 / 2;" + data-offset-x="0" data-offset-y="15" data-expected-width="15" data-expected-height="50"> + </div> + <div class="absolute" style="grid-column: 3 / foo; grid-row: 3 / foo;" + data-offset-x="315" data-offset-y="215" data-expected-width="215" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 2 / 3; grid-row: 3 / foo;" + data-offset-x="115" data-offset-y="215" data-expected-width="200" data-expected-height="115"> + </div> + <div class="absolute" style="grid-column: 3 / foo; grid-row: 2 / 3;" + data-offset-x="315" data-offset-y="65" data-expected-width="215" data-expected-height="150"> + </div> +</div> + +</body>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt index 8d5427d..5c0dd709 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set-expected.txt
@@ -174,6 +174,12 @@ PASS element.style.gridAutoColumns is "initial" PASS getComputedStyle(element, '').getPropertyValue('grid-auto-rows') is "auto" PASS element.style.gridAutoRows is "initial" + +Test the inherit value on reset-only subproperties (grid-*-gap) +PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap') is "0px" +PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap') is "0px" +PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap') is "20px" +PASS getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap') is "100px" PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html index 03cb376..e07282a 100644 --- a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html +++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-shorthand-get-set.html
@@ -1,4 +1,4 @@ -<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<!DOCTYPE html> <html> <head> <link href="resources/grid.css" rel="stylesheet"> @@ -109,6 +109,17 @@ testGridDefinitionsSetJSValues("column 10px / 20px", "none", "none", "none", "column", "10px", "20px", "initial", "initial", "initial", "column", "10px", "20px"); testGridDefinitionsSetJSValues("none", "none", "none", "none", "row", "auto", "auto", "none", "none", "none", "initial", "initial", "initial"); + debug(""); + debug("Test the inherit value on reset-only subproperties (grid-*-gap)"); + document.body.style.gridRowGap = "100px"; + document.body.style.gridColumnGap = "20px"; + var anotherElement = document.createElement("div"); + document.body.appendChild(anotherElement); + shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap')", "0px"); + shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap')", "0px"); + anotherElement.style.grid = "inherit"; + shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-column-gap')", "20px"); + shouldBeEqualToString("getComputedStyle(anotherElement, '').getPropertyValue('grid-row-gap')", "100px"); </script> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/hover-first-letter-sibling-expected.txt b/third_party/WebKit/LayoutTests/fast/css/invalidation/hover-first-letter-sibling-expected.txt new file mode 100644 index 0000000..f6f7944 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/hover-first-letter-sibling-expected.txt
@@ -0,0 +1,13 @@ +Sibling invalidation with :hover and ::first-letter + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS getComputedStyle(target).backgroundColor is transparent +PASS window.eventSender is defined. +PASS internals.updateStyleAndReturnAffectedElementCount() is 4 +PASS getComputedStyle(target).backgroundColor is green +PASS successfullyParsed is true + +TEST COMPLETE +This text, and the orange square, should have a green background when the orange square is hovered.
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/hover-first-letter-sibling.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/hover-first-letter-sibling.html new file mode 100644 index 0000000..f272920 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/hover-first-letter-sibling.html
@@ -0,0 +1,49 @@ +<!DOCTYPE html> +<script src="../../../resources/js-test.js"></script> +<style> + #hovered { width: 100px; height: 100px; background-color: orange } + #hovered::first-letter { color: lime } + #hovered:hover { background-color: green } + #hovered:hover + div #target { background-color: green } +</style> +<div id="hovered"> + <div></div> + <div></div> +</div> +<div> + <div></div> + <div></div> + <div></div> + <div></div> + <div></div> + <div id="target">This text, and the orange square, should have a green background when the orange square is hovered.</div> +</div> +<script> +description("Sibling invalidation with :hover and ::first-letter"); + +function hoverElement(element) { + eventSender.mouseMoveTo(0, 0); + document.body.offsetLeft; // force layout. + var x = element.offsetLeft + 1; + var y = element.offsetTop + 1; + eventSender.mouseMoveTo(x, y); +} + +var transparent = "rgba(0, 0, 0, 0)"; +var green = "rgb(0, 128, 0)"; + +shouldBe("getComputedStyle(target).backgroundColor", "transparent"); + +shouldBeDefined("window.eventSender"); + +if (window.eventSender) + hoverElement(hovered); + +// Recalc #hovered (1), its subtree (2) due to ::first-letter, and #target (1). +// In total: 4. +if (window.internals) + shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "4"); + +shouldBe("getComputedStyle(target).backgroundColor", "green"); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation-expected.txt b/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation-expected.txt index 2f0add2..1d826ed 100644 --- a/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation-expected.txt
@@ -4,7 +4,7 @@ PASS getComputedStyle(document.querySelector('.b')).color is "rgb(255, 0, 0)" -PASS internals.updateStyleAndReturnAffectedElementCount() is 6 +PASS internals.updateStyleAndReturnAffectedElementCount() is 2 PASS getComputedStyle(document.querySelector('.b')).color is "rgb(0, 128, 0)" PASS successfullyParsed is true
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation.html index a8b5a538..c9da3924 100644 --- a/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation.html +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/reattach-with-sibling-invalidation.html
@@ -27,10 +27,9 @@ // Trigger lazyReattachIfAttached() -> detach(). document.querySelector("input").type = "button"; - // The expected count will be 2 when ContainerNode::checkForChildrenAdjacentRuleChanges() - // is removed. One for attaching the input, and one for the span.b recalc. + // One for attaching the input, and one for the span.b recalc. if (window.internals) - shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "6"); + shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "2"); shouldBeEqualToString("getComputedStyle(document.querySelector('.b')).color", "rgb(0, 128, 0)"); </script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/sibling-inserted.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/sibling-inserted.html index b035d76..9c7e23c 100644 --- a/third_party/WebKit/LayoutTests/fast/css/invalidation/sibling-inserted.html +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/sibling-inserted.html
@@ -52,14 +52,13 @@ var t2 = document.createElement('div'); t2.id = 't2'; i2.parentNode.insertBefore(t2, i2); - assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 5, "Subtree style recalc"); + assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 4, "Subtree style recalc"); assert_equals(getComputedStyle(r2).backgroundColor, "rgb(0, 128, 0)", "Background color is green after class change"); }, "Insert before siblings"); test(function() { var d3 = document.getElementById('d3'); var r3 = document.getElementById('r3'); - assert_true(!!window.eventSender, "This test only works with eventSender present"); d3.parentNode.removeChild(d3); assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 3, "Subtree style recalc");
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/subtree-with-sibling-expected.txt b/third_party/WebKit/LayoutTests/fast/css/invalidation/subtree-with-sibling-expected.txt new file mode 100644 index 0000000..c28a980b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/subtree-with-sibling-expected.txt
@@ -0,0 +1,21 @@ +A subtree invalidation should not invalidation sibling forest + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS getComputedStyle(c1Spans[0]).backgroundColor is transparent +PASS getComputedStyle(c1Spans[1]).backgroundColor is transparent +PASS getComputedStyle(c2Spans[0]).backgroundColor is transparent +PASS getComputedStyle(c2Spans[1]).backgroundColor is transparent +PASS internals.updateStyleAndReturnAffectedElementCount() is 3 +PASS getComputedStyle(c1Spans[0]).backgroundColor is green +PASS getComputedStyle(c1Spans[1]).backgroundColor is green +PASS internals.updateStyleAndReturnAffectedElementCount() is 3 +PASS getComputedStyle(c2Spans[0]).backgroundColor is green +PASS getComputedStyle(c2Spans[1]).backgroundColor is green +PASS successfullyParsed is true + +TEST COMPLETE +This text should be green This text should be green +This text should be green This text should be green +
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/subtree-with-sibling.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/subtree-with-sibling.html new file mode 100644 index 0000000..ed113f0 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/subtree-with-sibling.html
@@ -0,0 +1,69 @@ +<!DOCTYPE html> +<script src="../../../resources/js-test.js"></script> +<style> +/* Rule to set childrenAffectedByDirectAdjacentRules() on #parent */ +div + #x { color: orange } + +/* Rule to cause subtree recalc on #c1 when className set to c1. */ +.c1 * { background-color: green } + +/* Rule to cause subtree recalc on div sibling of #c2 when className set to c2. */ +.c2 + div * { background-color: green } + +</style> +<div id="parent"> + <div id="c1"> + <span>This text should be green</span> + <span>This text should be green</span> + </div> + <div> + <span></span> + <span></span> + </div> + <div id="c2"> + <span></span> + <span></span> + </div> + <div> + <span>This text should be green</span> + <span>This text should be green</span> + </div> + <div> + <span></span> + <span></span> + </div> + <div id="x"></div> +</div> +<script> +description("A subtree invalidation should not invalidation sibling forest"); + +var transparent = "rgba(0, 0, 0, 0)"; +var green = "rgb(0, 128, 0)"; + +var c1Spans = c1.querySelectorAll("span"); +shouldBe("getComputedStyle(c1Spans[0]).backgroundColor", "transparent"); +shouldBe("getComputedStyle(c1Spans[1]).backgroundColor", "transparent"); + +var c2Spans = document.querySelectorAll("#c2 + div span"); +shouldBe("getComputedStyle(c2Spans[0]).backgroundColor", "transparent"); +shouldBe("getComputedStyle(c2Spans[1]).backgroundColor", "transparent"); + +document.body.offsetTop; // force recalc + +c1.className = "c1"; + +if (window.internals) + shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "3"); +shouldBe("getComputedStyle(c1Spans[0]).backgroundColor", "green"); +shouldBe("getComputedStyle(c1Spans[1]).backgroundColor", "green"); + +document.body.offsetTop; // force recalc + +c2.className = "c2"; + +if (window.internals) + shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "3"); +shouldBe("getComputedStyle(c2Spans[0]).backgroundColor", "green"); +shouldBe("getComputedStyle(c2Spans[1]).backgroundColor", "green"); + +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/content-element-change-select-attribute-after-deleted-crash.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/content-element-change-select-attribute-after-deleted-crash.html new file mode 100644 index 0000000..f7ed27e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/content-element-change-select-attribute-after-deleted-crash.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<script src='../../../resources/testharness.js'></script> +<script src='../../../resources/testharnessreport.js'></script> +<div id=host1></div> +<script> +'use strict'; +const sr = host1.createShadowRoot(); +sr.innerHTML = '<div id="host2"></div>'; +const sr2 = sr.getElementById('host2').createShadowRoot(); +sr.innerHTML = null; +// TODO(hayato): Find a more reliable way to reproduce the crash. This is the only reliable way as of now. +// Using GCController.collect() does not reproduce the crash. +for (var i = 1; i < 20000; i++) { + "abc" + i; +} +const selectTest = async_test("Testing select attribute change"); +setTimeout(() => { + selectTest.step(() => { + sr2.appendChild(document.createElement('content')).select = 'foo'; + }); + selectTest.done(); +}, 0); +</script>
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt b/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt index fa867ba..e27b96b 100644 --- a/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute-expected.txt
@@ -139,8 +139,8 @@ 8. targetDiv received mouseenter buttons: 1 9. targetDiv received mousemove buttons: 1 10. dragImg received dragstart buttons: 1 -11. dragImg received drag buttons: 0 -12. targetDiv received dragenter buttons: 0 +11. dragImg received drag buttons: 1 +12. targetDiv received dragenter buttons: 1 13. dragImg received drag buttons: 1 14. dragImg received dragenter buttons: 1 15. targetDiv received dragleave buttons: 1 @@ -165,8 +165,8 @@ 8. targetDiv received mouseenter buttons: 3 9. targetDiv received mousemove buttons: 3 10. dragImg received dragstart buttons: 3 -11. dragImg received drag buttons: 0 -12. targetDiv received dragenter buttons: 0 +11. dragImg received drag buttons: 3 +12. targetDiv received dragenter buttons: 3 13. dragImg received drag buttons: 3 14. dragImg received dragenter buttons: 3 15. targetDiv received dragleave buttons: 3 @@ -191,8 +191,8 @@ 8. targetDiv received mouseenter buttons: 7 9. targetDiv received mousemove buttons: 7 10. dragImg received dragstart buttons: 7 -11. dragImg received drag buttons: 0 -12. targetDiv received dragenter buttons: 0 +11. dragImg received drag buttons: 7 +12. targetDiv received dragenter buttons: 7 13. dragImg received drag buttons: 7 14. dragImg received dragenter buttons: 7 15. targetDiv received dragleave buttons: 7
diff --git a/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute.html b/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute.html index 2aed2d9e..e4ec117 100644 --- a/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute.html +++ b/third_party/WebKit/LayoutTests/fast/events/mouse-event-buttons-attribute.html
@@ -44,8 +44,6 @@ { initialButtons: [], action: longTapAction, showContextMenuOnMouseUp: false }, { initialButtons: [], action: longTapAction, showContextMenuOnMouseUp: true }, - - //TODO(nzolghadr): crbug.com/576290 "buttons" field seems to be set to 0 incorrectly in some events { initialButtons: [], action: dragDropAction }, { initialButtons: [R], action: dragDropAction }, { initialButtons: [M, R], action: dragDropAction },
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-resize-after-open-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-resize-after-open-expected.txt new file mode 100644 index 0000000..fd293e75 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-resize-after-open-expected.txt
@@ -0,0 +1,6 @@ +PASS popupWindow.innerWidth is 100 +PASS popupWindow.innerWidth is 150 +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-resize-after-open.html b/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-resize-after-open.html new file mode 100644 index 0000000..e2a360b --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/forms/select-popup/popup-menu-resize-after-open.html
@@ -0,0 +1,30 @@ +<!DOCTYPE html> +<script src="../../../resources/js-test.js"></script> +<script src="../resources/picker-common.js"></script> +<style> +#menu { + -webkit-appearance: none; + width: 100px; +} +</style> +<select id="menu"> +<option>o1</option> +<option>o2</option> +</select> +<script> +function openPickerErrorCallback() { + testFailed('picker didn\'t open') + finishJSTest(); +} +function checkPopupWidth() { + shouldBe('popupWindow.innerWidth', '150'); + finishJSTest(); +} +var menu = document.getElementById('menu'); +openPicker(menu, function() { + shouldBe('popupWindow.innerWidth', '100'); + menu.style.width = "150px"; + menu.offsetTop; + setTimeout(checkPopupWidth, 10); +}, openPickerErrorCallback); +</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/download_resources.html b/third_party/WebKit/LayoutTests/http/tests/preload/download_resources.html index dfee90ad..aae995e 100644 --- a/third_party/WebKit/LayoutTests/http/tests/preload/download_resources.html +++ b/third_party/WebKit/LayoutTests/http/tests/preload/download_resources.html
@@ -9,11 +9,19 @@ <link rel=preload href="../resources/square.png" as=image> <link rel=preload href="../resources/square.png?background" as=image> <link rel=preload href="../resources/Ahem.ttf" as=font crossorigin> +<link rel=preload href="../resources/test.mp4" as=video> +<link rel=preload href="../resources/test.oga" as=audio> +<link rel=preload href="../security/resources/captions.vtt" as=track> +<link rel=preload href="../resources/dummy.xml" as=foobarxmlthing> +<link rel=preload href="../resources/dummy.xml"> <script src="../resources/slow-script.pl?delay=200"></script> <script> window.addEventListener("load", t.step_func(function() { - assert_equals(performance.getEntriesByType("resource").length, 8); + var entries = performance.getEntriesByType("resource"); + for (var i = 0; i < entries.length; ++i) { + console.log(entries[i].name); + } + assert_equals(performance.getEntriesByType("resource").length, 12); t.done(); })); </script> -
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/single_download_preload.html b/third_party/WebKit/LayoutTests/http/tests/preload/single_download_preload.html index 059bb8b..a2eae135 100644 --- a/third_party/WebKit/LayoutTests/http/tests/preload/single_download_preload.html +++ b/third_party/WebKit/LayoutTests/http/tests/preload/single_download_preload.html
@@ -9,6 +9,11 @@ <link rel=preload href="../resources/square.png" as=image> <link rel=preload href="../resources/square.png?background" as=image> <link rel=preload href="../resources/Ahem.ttf" as=font crossorigin> +<link rel=preload href="../resources/test.mp4" as=video> +<link rel=preload href="../resources/test.oga" as=audio> +<link rel=preload href="../resources/security/captions.vtt" as=track> +<link rel=preload href="../resources/dummy.xml" as=foobarxmlthing> +<link rel=preload href="../resources/dummy.xml"> <script src="../resources/slow-script.pl?delay=200"></script> <style> #background { @@ -26,9 +31,17 @@ <script src="../resources/dummy.js"></script> <div id="background"></div> <img src="../resources/square.png"> +<video src="../resources/test.mp4"> + <track kind=subtitles src="../resources/security/captions.vtt" srclang=en> +</video> +<audio src="../resources/test/oga"></audio> <script> + var xhr = new XMLHttpRequest(); + xhr.open("GET", "../resources/dummy.xml"); + xhr.send(); + window.addEventListener("load", t.step_func(function() { - assert_equals(performance.getEntriesByType("resource").length, 8); + assert_equals(performance.getEntriesByType("resource").length, 12); t.done(); })); </script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/resources/test.oga b/third_party/WebKit/LayoutTests/http/tests/resources/test.oga new file mode 100644 index 0000000..4544688 --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/resources/test.oga Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/resources/global-interface-listing-worker.js b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/resources/global-interface-listing-worker.js index e63eb56..3911fd0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/resources/global-interface-listing-worker.js +++ b/third_party/WebKit/LayoutTests/http/tests/serviceworker/webexposed/resources/global-interface-listing-worker.js
@@ -31,8 +31,10 @@ 'Number', 'Object', 'Promise', + 'Proxy', 'RangeError', 'ReferenceError', + 'Reflect', 'RegExp', 'Set', 'String',
diff --git a/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt b/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt index 7db184a9..0bbe50d 100644 --- a/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/file-system-project-expected.txt
@@ -67,3 +67,12 @@ - file:///var/www3/html/foo.js - file:///var/www3/bar.js +Running: testFileAddedExternally +-- Original tree -- +Dumping uiSourceCodes origin URLs: + - file:///var/www4/html/foo.js +-- File added externally -- +Dumping uiSourceCodes origin URLs: + - file:///var/www4/html/foo.js + - file:///var/www4/html/bar.js +
diff --git a/third_party/WebKit/LayoutTests/inspector/file-system-project.html b/third_party/WebKit/LayoutTests/inspector/file-system-project.html index 8db14a9..ae72afd 100644 --- a/third_party/WebKit/LayoutTests/inspector/file-system-project.html +++ b/third_party/WebKit/LayoutTests/inspector/file-system-project.html
@@ -184,6 +184,28 @@ fs.reportRemoved(); next(); } + }, + + function testFileAddedExternally(next) + { + var fs = new InspectorTest.TestFileSystem("file:///var/www4"); + var dir = fs.root.mkdir("html"); + dir.addFile("foo.js", ""); + fs.reportCreated(dumpFileSystem); + + function dumpFileSystem() + { + InspectorTest.addResult("-- Original tree --"); + dumpWorkspaceUISourceCodes(); + + dir.addFile("bar.js", ""); + InspectorFrontendHost.events.dispatchEventToListeners(InspectorFrontendHostAPI.Events.FileSystemFilesChanged, ["/var/www4/html/bar.js"]); + + InspectorTest.addResult("-- File added externally --"); + dumpWorkspaceUISourceCodes(); + fs.reportRemoved(); + next(); + } } ]); };
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/replaced/border-radius-clip-expected.png new file mode 100644 index 0000000..be9b9e4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/android/http/tests/media/video-buffered-range-contains-currentTime-expected.png new file mode 100644 index 0000000..b4da1a9 --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/android/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/border-radius-clip-expected.png index be9b9e4..41dc031 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png index b4da1a9..addd95a4 100644 --- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/replaced/border-radius-clip-expected.png index 3746cb8..47d5744 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-lion/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-lion/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/replaced/border-radius-clip-expected.png index d8c7253..2850457b 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-mavericks/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/replaced/border-radius-clip-expected.png new file mode 100644 index 0000000..ed4538b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-mountainlion/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/replaced/border-radius-clip-expected.png new file mode 100644 index 0000000..ed4538b --- /dev/null +++ b/third_party/WebKit/LayoutTests/platform/mac-retina/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/replaced/border-radius-clip-expected.png index 946cbe3..8c495fee 100644 --- a/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac-snowleopard/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/border-radius-clip-expected.png index d36a6fc7..f4b1d04 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png index 7175c06c..aaf2ed1 100644 --- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/fast/replaced/border-radius-clip-expected.png index 3919ba7f..1a60bc91 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win-xp/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win-xp/http/tests/media/video-buffered-range-contains-currentTime-expected.png index 4af3229..f4fcefa 100644 --- a/third_party/WebKit/LayoutTests/platform/win-xp/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win-xp/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/border-radius-clip-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/border-radius-clip-expected.png index 5ad88e20..f7d5770 100644 --- a/third_party/WebKit/LayoutTests/platform/win/fast/replaced/border-radius-clip-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/fast/replaced/border-radius-clip-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png index f5f2a61a..b9ff2a55 100644 --- a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png +++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png Binary files differ
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt index 5f37ee3..dad3d9b5 100644 --- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -4410,9 +4410,9 @@ method removeItem method replaceItem interface SVGUnitTypes - static attribute SVG_UNIT_TYPE_OBJECTBOUNDINGBOX - static attribute SVG_UNIT_TYPE_UNKNOWN - static attribute SVG_UNIT_TYPE_USERSPACEONUSE + attribute SVG_UNIT_TYPE_OBJECTBOUNDINGBOX + attribute SVG_UNIT_TYPE_UNKNOWN + attribute SVG_UNIT_TYPE_USERSPACEONUSE method constructor interface SVGUseElement : SVGGraphicsElement getter height @@ -4432,9 +4432,9 @@ method constructor setter zoomAndPan interface SVGViewSpec - static attribute SVG_ZOOMANDPAN_DISABLE - static attribute SVG_ZOOMANDPAN_MAGNIFY - static attribute SVG_ZOOMANDPAN_UNKNOWN + attribute SVG_ZOOMANDPAN_DISABLE + attribute SVG_ZOOMANDPAN_MAGNIFY + attribute SVG_ZOOMANDPAN_UNKNOWN getter preserveAspectRatio getter preserveAspectRatioString getter transform
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt index c27f329..dae8888 100644 --- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt +++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -332,6 +332,7 @@ interface BluetoothGATTRemoteServer getter connected method constructor + method disconnect method getPrimaryService interface BluetoothGATTService getter isPrimary @@ -485,21 +486,6 @@ getter vmin getter vw method constructor - setter ch - setter cm - setter em - setter ex - setter in - setter mm - setter pc - setter percent - setter pt - setter px - setter rem - setter vh - setter vmax - setter vmin - setter vw interface CanvasCaptureMediaStreamTrack : MediaStreamTrack getter canvas method constructor @@ -5013,9 +4999,9 @@ method removeItem method replaceItem interface SVGUnitTypes - static attribute SVG_UNIT_TYPE_OBJECTBOUNDINGBOX - static attribute SVG_UNIT_TYPE_UNKNOWN - static attribute SVG_UNIT_TYPE_USERSPACEONUSE + attribute SVG_UNIT_TYPE_OBJECTBOUNDINGBOX + attribute SVG_UNIT_TYPE_UNKNOWN + attribute SVG_UNIT_TYPE_USERSPACEONUSE method constructor interface SVGUseElement : SVGGraphicsElement getter height @@ -5035,9 +5021,9 @@ method constructor setter zoomAndPan interface SVGViewSpec - static attribute SVG_ZOOMANDPAN_DISABLE - static attribute SVG_ZOOMANDPAN_MAGNIFY - static attribute SVG_ZOOMANDPAN_UNKNOWN + attribute SVG_ZOOMANDPAN_DISABLE + attribute SVG_ZOOMANDPAN_MAGNIFY + attribute SVG_ZOOMANDPAN_UNKNOWN getter preserveAspectRatio getter preserveAspectRatioString getter transform
diff --git a/third_party/WebKit/LayoutTests/webexposed/resources/global-interface-listing.js b/third_party/WebKit/LayoutTests/webexposed/resources/global-interface-listing.js index ead5202b..aab287c 100644 --- a/third_party/WebKit/LayoutTests/webexposed/resources/global-interface-listing.js +++ b/third_party/WebKit/LayoutTests/webexposed/resources/global-interface-listing.js
@@ -57,8 +57,10 @@ 'Number', 'Object', 'Promise', + 'Proxy', 'RangeError', 'ReferenceError', + 'Reflect', 'RegExp', 'Set', 'String',
diff --git a/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl b/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl index ef65b74..0549484 100644 --- a/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl +++ b/third_party/WebKit/Source/build/scripts/templates/StylePropertyShorthand.h.tmpl
@@ -32,7 +32,6 @@ public: StylePropertyShorthand() : m_properties(0) - , m_propertiesForInitialization(0) , m_length(0) , m_shorthandID(CSSPropertyInvalid) { @@ -40,28 +39,17 @@ StylePropertyShorthand(CSSPropertyID id, const CSSPropertyID* properties, unsigned numProperties) : m_properties(properties) - , m_propertiesForInitialization(0) - , m_length(numProperties) - , m_shorthandID(id) - { - } - - StylePropertyShorthand(CSSPropertyID id, const CSSPropertyID* properties, const StylePropertyShorthand** propertiesForInitialization, unsigned numProperties) - : m_properties(properties) - , m_propertiesForInitialization(propertiesForInitialization) , m_length(numProperties) , m_shorthandID(id) { } const CSSPropertyID* properties() const { return m_properties; } - const StylePropertyShorthand** propertiesForInitialization() const { return m_propertiesForInitialization; } unsigned length() const { return m_length; } CSSPropertyID id() const { return m_shorthandID; } private: const CSSPropertyID* m_properties; - const StylePropertyShorthand** m_propertiesForInitialization; unsigned m_length; CSSPropertyID m_shorthandID; };
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index 837757e..bfedd0d1 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi
@@ -3967,6 +3967,7 @@ 'html/HTMLVideoElementTest.cpp', 'html/LinkRelAttributeTest.cpp', 'html/TimeRangesTest.cpp', + 'html/canvas/CanvasAsyncBlobCreatorTest.cpp', 'html/canvas/CanvasFontCacheTest.cpp', 'html/forms/EmailInputTypeTest.cpp', 'html/forms/FileInputTypeTest.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSProperties.in b/third_party/WebKit/Source/core/css/CSSProperties.in index 7f646cc4..ca7cc71 100644 --- a/third_party/WebKit/Source/core/css/CSSProperties.in +++ b/third_party/WebKit/Source/core/css/CSSProperties.in
@@ -463,7 +463,7 @@ flex longhands=flex-grow;flex-shrink;flex-basis flex-flow longhands=flex-direction;flex-wrap font longhands=font-style;font-variant;font-weight;font-stretch;font-size;line-height;font-family -grid runtime_flag=CSSGridLayout, longhands=grid-template-columns;grid-template-rows;grid-template-areas;grid-auto-flow;grid-auto-columns;grid-auto-rows +grid runtime_flag=CSSGridLayout, longhands=grid-template-columns;grid-template-rows;grid-template-areas;grid-auto-flow;grid-auto-columns;grid-auto-rows;grid-column-gap;grid-row-gap grid-area runtime_flag=CSSGridLayout, longhands=grid-row-start;grid-column-start;grid-row-end;grid-column-end grid-column runtime_flag=CSSGridLayout, longhands=grid-column-start;grid-column-end grid-gap runtime_flag=CSSGridLayout, longhands=grid-column-gap;grid-row-gap
diff --git a/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp b/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp index ae85bce..d91cbb3 100644 --- a/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp +++ b/third_party/WebKit/Source/core/css/StylePropertyShorthandCustom.cpp
@@ -23,18 +23,6 @@ namespace blink { -const StylePropertyShorthand& borderShorthandForParsing() -{ - static const CSSPropertyID borderShorthandProperties[] = { CSSPropertyBorderWidth, CSSPropertyBorderStyle, CSSPropertyBorderColor }; - static const StylePropertyShorthand* propertiesForInitialization[] = { - &borderWidthShorthand(), - &borderStyleShorthand(), - &borderColorShorthand(), - }; - DEFINE_STATIC_LOCAL(StylePropertyShorthand, borderForParsingLonghands, (CSSPropertyBorder, borderShorthandProperties, propertiesForInitialization, WTF_ARRAY_LENGTH(borderShorthandProperties))); - return borderForParsingLonghands; -} - const StylePropertyShorthand& animationShorthandForParsing() { // When we parse the animation shorthand we need to look for animation-name
diff --git a/third_party/WebKit/Source/core/css/cssom/CalcLength.idl b/third_party/WebKit/Source/core/css/cssom/CalcLength.idl index 0a4e860f..79b2d2c 100644 --- a/third_party/WebKit/Source/core/css/cssom/CalcLength.idl +++ b/third_party/WebKit/Source/core/css/cssom/CalcLength.idl
@@ -5,19 +5,19 @@ RaisesException=Constructor, RuntimeEnabled=CSSTypedOM ] interface CalcLength : LengthValue { - attribute double? px; - attribute double? percent; - attribute double? em; - attribute double? ex; - attribute double? ch; - attribute double? rem; - attribute double? vw; - attribute double? vh; - attribute double? vmin; - attribute double? vmax; - attribute double? cm; - attribute double? mm; - attribute double? in; - attribute double? pc; - attribute double? pt; + readonly attribute double? px; + readonly attribute double? percent; + readonly attribute double? em; + readonly attribute double? ex; + readonly attribute double? ch; + readonly attribute double? rem; + readonly attribute double? vw; + readonly attribute double? vh; + readonly attribute double? vmin; + readonly attribute double? vmax; + readonly attribute double? cm; + readonly attribute double? mm; + readonly attribute double? in; + readonly attribute double? pc; + readonly attribute double? pt; };
diff --git a/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h b/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h index 1889085..d086926 100644 --- a/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h +++ b/third_party/WebKit/Source/core/css/cssom/StyleCalcLength.h
@@ -23,27 +23,26 @@ return create(length); } -#define GETTER_SETTER_MACRO(name, capsName, index) \ - double name(bool& isNull) { isNull = !has(index); return get(index); } \ - void set##capsName(double value) { set(value, index); } +#define GETTER_MACRO(name, index) \ + double name(bool& isNull) { isNull = !has(index); return get(index); } - GETTER_SETTER_MACRO(px, Px, LengthUnit::Px) - GETTER_SETTER_MACRO(percent, Percent, LengthUnit::Percent) - GETTER_SETTER_MACRO(em, Em, LengthUnit::Em) - GETTER_SETTER_MACRO(ex, Ex, LengthUnit::Ex) - GETTER_SETTER_MACRO(ch, Ch, LengthUnit::Ch) - GETTER_SETTER_MACRO(rem, Rem, LengthUnit::Rem) - GETTER_SETTER_MACRO(vw, Vw, LengthUnit::Vw) - GETTER_SETTER_MACRO(vh, Vh, LengthUnit::Vh) - GETTER_SETTER_MACRO(vmin, Vmin, LengthUnit::Vmin) - GETTER_SETTER_MACRO(vmax, Vmax, LengthUnit::Vmax) - GETTER_SETTER_MACRO(cm, Cm, LengthUnit::Cm) - GETTER_SETTER_MACRO(mm, Mm, LengthUnit::Mm) - GETTER_SETTER_MACRO(in, In, LengthUnit::In) - GETTER_SETTER_MACRO(pc, Pc, LengthUnit::Pc) - GETTER_SETTER_MACRO(pt, Pt, LengthUnit::Pt) + GETTER_MACRO(px, LengthUnit::Px) + GETTER_MACRO(percent, LengthUnit::Percent) + GETTER_MACRO(em, LengthUnit::Em) + GETTER_MACRO(ex, LengthUnit::Ex) + GETTER_MACRO(ch, LengthUnit::Ch) + GETTER_MACRO(rem, LengthUnit::Rem) + GETTER_MACRO(vw, LengthUnit::Vw) + GETTER_MACRO(vh, LengthUnit::Vh) + GETTER_MACRO(vmin, LengthUnit::Vmin) + GETTER_MACRO(vmax, LengthUnit::Vmax) + GETTER_MACRO(cm, LengthUnit::Cm) + GETTER_MACRO(mm, LengthUnit::Mm) + GETTER_MACRO(in, LengthUnit::In) + GETTER_MACRO(pc, LengthUnit::Pc) + GETTER_MACRO(pt, LengthUnit::Pt) -#undef GETTER_SETTER_MACRO +#undef GETTER_MACRO String cssString() const override; PassRefPtrWillBeRawPtr<CSSValue> toCSSValue() const override;
diff --git a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp index 5de3aa11..67c96eb 100644 --- a/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp +++ b/third_party/WebKit/Source/core/css/invalidation/StyleInvalidator.cpp
@@ -177,12 +177,7 @@ if (const DescendantInvalidationSet* descendants = invalidationSet.siblingDescendants()) { if (descendants->wholeSubtreeInvalid()) { - // Avoid directly setting SubtreeStyleChange on element, or ContainerNode::checkForChildrenAdjacentRuleChanges() - // may propagate the SubtreeStyleChange to our own siblings' subtrees. - - for (Element* child = ElementTraversal::firstChild(element); child; child = ElementTraversal::nextSibling(*child)) { - child->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); - } + element.setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::StyleInvalidator)); return true; } @@ -202,6 +197,9 @@ for (const auto& invalidationSet : pendingInvalidations->siblings()) siblingData.pushInvalidationSet(toSiblingInvalidationSet(*invalidationSet)); + if (element.styleChangeType() >= SubtreeStyleChange) + return; + if (!pendingInvalidations->descendants().isEmpty()) { for (const auto& invalidationSet : pendingInvalidations->descendants()) recursionData.pushInvalidationSet(toDescendantInvalidationSet(*invalidationSet)); @@ -216,17 +214,21 @@ ALWAYS_INLINE bool StyleInvalidator::checkInvalidationSetsAgainstElement(Element& element, RecursionData& recursionData, SiblingData& siblingData) { - if (element.styleChangeType() >= SubtreeStyleChange || recursionData.wholeSubtreeInvalid()) { - recursionData.setWholeSubtreeInvalid(); + if (recursionData.wholeSubtreeInvalid()) return false; - } - bool thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationSets(element); - if (UNLIKELY(!siblingData.isEmpty())) - thisElementNeedsStyleRecalc |= siblingData.matchCurrentInvalidationSets(element, recursionData); + bool thisElementNeedsStyleRecalc = false; + if (element.styleChangeType() >= SubtreeStyleChange) { + recursionData.setWholeSubtreeInvalid(); + } else { + thisElementNeedsStyleRecalc = recursionData.matchesCurrentInvalidationSets(element); + if (UNLIKELY(!siblingData.isEmpty())) + thisElementNeedsStyleRecalc |= siblingData.matchCurrentInvalidationSets(element, recursionData); + } if (UNLIKELY(element.needsStyleInvalidation())) pushInvalidationSetsForElement(element, recursionData, siblingData); + return thisElementNeedsStyleRecalc; }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp index 7cc55e5..170c520 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -2006,27 +2006,27 @@ return consumeColor(range, cssParserMode); } -static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeLineWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode) +static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeLineWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless) { CSSValueID id = range.peek().id(); if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) return consumeIdent(range); - return consumeLength(range, cssParserMode, ValueRangeNonNegative); + return consumeLength(range, cssParserMode, ValueRangeNonNegative, unitless); } -static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeBorderWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode) +static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeBorderWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode, UnitlessQuirk unitless) { - return consumeLineWidth(range, cssParserMode); + return consumeLineWidth(range, cssParserMode, unitless); } static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeTextStrokeWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode) { - return consumeLineWidth(range, cssParserMode); + return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid); } static PassRefPtrWillBeRawPtr<CSSPrimitiveValue> consumeColumnRuleWidth(CSSParserTokenRange& range, CSSParserMode cssParserMode) { - return consumeLineWidth(range, cssParserMode); + return consumeLineWidth(range, cssParserMode, UnitlessQuirk::Forbid); } static bool consumeTranslate3d(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtrWillBeRawPtr<CSSFunctionValue>& transformValue) @@ -2947,6 +2947,11 @@ PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty) { CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty); + if (CSSParserFastPaths::isKeywordPropertyID(property)) { + if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(property, m_range.peek().id())) + return nullptr; + return consumeIdent(m_range); + } switch (property) { case CSSPropertyWillChange: return consumeWillChange(m_range); @@ -3101,7 +3106,24 @@ case CSSPropertyWebkitBorderEndWidth: case CSSPropertyWebkitBorderBeforeWidth: case CSSPropertyWebkitBorderAfterWidth: - return consumeBorderWidth(m_range, m_context.mode()); + return consumeBorderWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid); + case CSSPropertyBorderBottomColor: + case CSSPropertyBorderLeftColor: + case CSSPropertyBorderRightColor: + case CSSPropertyBorderTopColor: { + bool allowQuirkyColors = inQuirksMode() + && (m_currentShorthand == CSSPropertyInvalid || m_currentShorthand == CSSPropertyBorderColor); + return consumeColor(m_range, m_context.mode(), allowQuirkyColors); + } + case CSSPropertyBorderBottomWidth: + case CSSPropertyBorderLeftWidth: + case CSSPropertyBorderRightWidth: + case CSSPropertyBorderTopWidth: { + bool allowQuirkyLengths = inQuirksMode() + && (m_currentShorthand == CSSPropertyInvalid || m_currentShorthand == CSSPropertyBorderWidth); + UnitlessQuirk unitless = allowQuirkyLengths ? UnitlessQuirk::Allow : UnitlessQuirk::Forbid; + return consumeBorderWidth(m_range, m_context.mode(), unitless); + } case CSSPropertyZIndex: return consumeZIndex(m_range); case CSSPropertyTextShadow: // CSS2 property, dropped in CSS2.1, back in CSS3, so treat as CSS3 @@ -3131,7 +3153,7 @@ case CSSPropertyOutlineOffset: return consumeLength(m_range, m_context.mode(), ValueRangeAll); case CSSPropertyOutlineWidth: - return consumeLineWidth(m_range, m_context.mode()); + return consumeLineWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid); case CSSPropertyTransform: return consumeTransform(m_range, m_context.mode(), unresolvedProperty == CSSPropertyAliasWebkitTransform); case CSSPropertyWebkitTransformOriginX: @@ -3596,13 +3618,7 @@ for (size_t i = 0; !foundLonghand && i < shorthand.length(); ++i) { if (longhands[i]) continue; - // TODO: parseSingleValue needs to handle fastpath keywords. - if (CSSParserFastPaths::isKeywordPropertyID(shorthandProperties[i])) { - if (CSSParserFastPaths::isValidKeywordPropertyAndValue(shorthandProperties[i], m_range.peek().id())) - longhands[i] = consumeIdent(m_range); - } else { - longhands[i] = parseSingleValue(shorthandProperties[i]); - } + longhands[i] = parseSingleValue(shorthandProperties[i]); if (longhands[i]) foundLonghand = true; } @@ -3675,6 +3691,40 @@ return true; } +bool CSSPropertyParser::consumeBorder(bool important) +{ + RefPtrWillBeRawPtr<CSSValue> width = nullptr; + RefPtrWillBeRawPtr<CSSValue> style = nullptr; + RefPtrWillBeRawPtr<CSSValue> color = nullptr; + + while (!width || !style || !color) { + if (!width && (width = consumeLineWidth(m_range, m_context.mode(), UnitlessQuirk::Forbid))) + continue; + if (!style && (style = parseSingleValue(CSSPropertyBorderLeftStyle))) + continue; + if (!color && (color = consumeColor(m_range, m_context.mode()))) + continue; + break; + } + + if (!width && !style && !color) + return false; + + if (!width) + width = cssValuePool().createImplicitInitialValue(); + if (!style) + style = cssValuePool().createImplicitInitialValue(); + if (!color) + color = cssValuePool().createImplicitInitialValue(); + + addExpandedPropertyForValue(CSSPropertyBorderWidth, width.release(), important); + addExpandedPropertyForValue(CSSPropertyBorderStyle, style.release(), important); + addExpandedPropertyForValue(CSSPropertyBorderColor, color.release(), important); + addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important); + + return m_range.atEnd(); +} + bool CSSPropertyParser::consume4Values(const StylePropertyShorthand& shorthand, bool important) { ASSERT(shorthand.length() == 4); @@ -3864,6 +3914,22 @@ addProperty(CSSPropertyBorderBottomLeftRadius, CSSValuePair::create(horizontalRadii[3].release(), verticalRadii[3].release(), CSSValuePair::DropIdenticalValues), important); return true; } + case CSSPropertyBorderColor: + return consume4Values(borderColorShorthand(), important); + case CSSPropertyBorderStyle: + return consume4Values(borderStyleShorthand(), important); + case CSSPropertyBorderWidth: + return consume4Values(borderWidthShorthand(), important); + case CSSPropertyBorderTop: + return consumeShorthandGreedily(borderTopShorthand(), important); + case CSSPropertyBorderRight: + return consumeShorthandGreedily(borderRightShorthand(), important); + case CSSPropertyBorderBottom: + return consumeShorthandGreedily(borderBottomShorthand(), important); + case CSSPropertyBorderLeft: + return consumeShorthandGreedily(borderLeftShorthand(), important); + case CSSPropertyBorder: + return consumeBorder(important); default: m_currentShorthand = oldShorthand; CSSParserValueList valueList(m_range);
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h index efafded..d13ae72 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h +++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -132,15 +132,14 @@ void addProperty(CSSPropertyID, PassRefPtrWillBeRawPtr<CSSValue>, bool important, bool implicit = false); void addExpandedPropertyForValue(CSSPropertyID propId, PassRefPtrWillBeRawPtr<CSSValue>, bool); + bool consumeBorder(bool important); + PassRefPtrWillBeRawPtr<CSSPrimitiveValue> parseValidPrimitive(CSSValueID ident, CSSParserValue*); - bool parseShorthand(CSSPropertyID, const StylePropertyShorthand&, bool important); bool parseShorthand(CSSPropertyID, bool important); bool consumeShorthandGreedily(const StylePropertyShorthand&, bool important); bool consume4Values(const StylePropertyShorthand&, bool important); - bool parse4Values(CSSPropertyID, const CSSPropertyID* properties, bool important); - bool parseFillImage(CSSParserValueList*, RefPtrWillBeRawPtr<CSSValue>&); enum FillPositionFlag { InvalidFillPosition = 0, AmbiguousFillPosition = 1, XFillPosition = 2, YFillPosition = 4 };
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp index c3a608a..8f8fa67 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParser.cpp
@@ -130,31 +130,59 @@ return CSSSelectorList::adoptSelectorVector(selectorList); } +namespace { + +enum CompoundSelectorFlags { + HasPseudoElementForRightmostCompound = 1 << 0, + HasContentPseudoElement = 1 << 1 +}; + +unsigned extractCompoundFlags(const CSSParserSelector& simpleSelector, CSSParserMode parserMode) +{ + if (simpleSelector.match() != CSSSelector::PseudoElement) + return 0; + if (simpleSelector.pseudoType() == CSSSelector::PseudoContent) + return HasContentPseudoElement; + if (simpleSelector.pseudoType() == CSSSelector::PseudoShadow) + return 0; + // TODO(rune@opera.com): crbug.com/578131 + // The UASheetMode check is a work-around to allow this selector in mediaControls(New).css: + // input[type="range" i]::-webkit-media-slider-container > div { + if (parserMode == UASheetMode && simpleSelector.pseudoType() == CSSSelector::PseudoWebKitCustomElement) + return 0; + return HasPseudoElementForRightmostCompound; +} + +} // namespace + PassOwnPtr<CSSParserSelector> CSSSelectorParser::consumeComplexSelector(CSSParserTokenRange& range) { OwnPtr<CSSParserSelector> selector = consumeCompoundSelector(range); if (!selector) return nullptr; - bool previousCompoundHasContentPseudo = false; - for (CSSParserSelector* simple = selector.get(); simple && !previousCompoundHasContentPseudo; simple = simple->tagHistory()) - previousCompoundHasContentPseudo = simple->pseudoType() == CSSSelector::PseudoContent; + unsigned previousCompoundFlags = 0; + + for (CSSParserSelector* simple = selector.get(); simple && !previousCompoundFlags; simple = simple->tagHistory()) + previousCompoundFlags |= extractCompoundFlags(*simple, m_context.mode()); while (CSSSelector::Relation combinator = consumeCombinator(range)) { OwnPtr<CSSParserSelector> nextSelector = consumeCompoundSelector(range); if (!nextSelector) return combinator == CSSSelector::Descendant ? selector.release() : nullptr; + if (previousCompoundFlags & HasPseudoElementForRightmostCompound) + return nullptr; CSSParserSelector* end = nextSelector.get(); - bool compoundHasContentPseudo = end->pseudoType() == CSSSelector::PseudoContent; + unsigned compoundFlags = extractCompoundFlags(*end, m_context.mode()); while (end->tagHistory()) { end = end->tagHistory(); - compoundHasContentPseudo |= end->pseudoType() == CSSSelector::PseudoContent; + compoundFlags |= extractCompoundFlags(*end, m_context.mode()); } end->setRelation(combinator); - if (previousCompoundHasContentPseudo) + if (previousCompoundFlags & HasContentPseudoElement) end->setRelationIsAffectedByPseudoContent(); - previousCompoundHasContentPseudo = compoundHasContentPseudo; + previousCompoundFlags = compoundFlags; end->setTagHistory(selector.release()); selector = nextSelector.release();
diff --git a/third_party/WebKit/Source/core/css/parser/CSSSelectorParserTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSSelectorParserTest.cpp index eda8efff..539c130 100644 --- a/third_party/WebKit/Source/core/css/parser/CSSSelectorParserTest.cpp +++ b/third_party/WebKit/Source/core/css/parser/CSSSelectorParserTest.cpp
@@ -203,10 +203,52 @@ TEST(CSSSelectorParserTest, WorkaroundForInvalidCustomPseudoInUAStyle) { // See crbug.com/578131 - CSSTokenizer::Scope scope("video::-webkit-media-text-track-region-container.scrolling"); - CSSParserTokenRange range = scope.tokenRange(); - CSSSelectorList list = CSSSelectorParser::parseSelector(range, CSSParserContext(UASheetMode, nullptr), nullptr); - EXPECT_TRUE(list.isValid()); + const char* testCases[] = { + "video::-webkit-media-text-track-region-container.scrolling", + "input[type=\"range\" i]::-webkit-media-slider-container > div" + }; + + for (auto testCase : testCases) { + CSSTokenizer::Scope scope(testCase); + CSSParserTokenRange range = scope.tokenRange(); + CSSSelectorList list = CSSSelectorParser::parseSelector(range, CSSParserContext(UASheetMode, nullptr), nullptr); + EXPECT_TRUE(list.isValid()); + } +} + +TEST(CSSSelectorParserTest, ValidPseudoElementInNonRightmostCompound) +{ + const char* testCases[] = { + "::content *", + "::shadow *", + "::content div::before", + "::shadow ::first-letter" + }; + + for (auto testCase : testCases) { + CSSTokenizer::Scope scope(testCase); + CSSParserTokenRange range = scope.tokenRange(); + CSSSelectorList list = CSSSelectorParser::parseSelector(range, CSSParserContext(HTMLStandardMode, nullptr), nullptr); + EXPECT_TRUE(list.isValid()); + } +} + +TEST(CSSSelectorParserTest, InvalidPseudoElementInNonRightmostCompound) +{ + const char* testCases[] = { + "::-webkit-volume-slider *", + "::before *", + "::-webkit-scrollbar *", + "::cue *", + "::selection *" + }; + + for (auto testCase : testCases) { + CSSTokenizer::Scope scope(testCase); + CSSParserTokenRange range = scope.tokenRange(); + CSSSelectorList list = CSSSelectorParser::parseSelector(range, CSSParserContext(HTMLStandardMode, nullptr), nullptr); + EXPECT_FALSE(list.isValid()); + } } } // namespace
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp index 0a55dcc..d298070 100644 --- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp +++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -315,26 +315,12 @@ CSSValueID id = value->id; - // TODO(timloh): Move to parseSingleValue - if (CSSParserFastPaths::isKeywordPropertyID(propId)) { - if (!CSSParserFastPaths::isValidKeywordPropertyAndValue(propId, id)) - return nullptr; - if (m_valueList->next() && !inShorthand()) - return nullptr; - return cssValuePool().createIdentifierValue(id); - } - bool validPrimitive = false; - Units unitless = FUnknown; RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr; switch (propId) { case CSSPropertyBackgroundColor: // <color> | inherit - case CSSPropertyBorderTopColor: // <color> | inherit - case CSSPropertyBorderRightColor: - case CSSPropertyBorderBottomColor: - case CSSPropertyBorderLeftColor: - parsedValue = parseColor(m_valueList->current(), inQuirksMode() && (!inShorthand() || m_currentShorthand == CSSPropertyBorderColor)); + parsedValue = parseColor(m_valueList->current(), inQuirksMode() && !inShorthand()); if (parsedValue) m_valueList->next(); break; @@ -379,18 +365,6 @@ m_valueList->next(); break; - case CSSPropertyBorderTopWidth: //// <border-width> | inherit - case CSSPropertyBorderRightWidth: // Which is defined as - case CSSPropertyBorderBottomWidth: // thin | medium | thick | <length> - case CSSPropertyBorderLeftWidth: - if (!inShorthand() || m_currentShorthand == CSSPropertyBorderWidth) - unitless = FUnitlessQuirk; - if (id == CSSValueThin || id == CSSValueMedium || id == CSSValueThick) - validPrimitive = true; - else - validPrimitive = validUnit(value, FLength | FNonNeg | unitless); - break; - case CSSPropertyBottom: // <length> | <percentage> | auto | inherit case CSSPropertyLeft: // <length> | <percentage> | auto | inherit case CSSPropertyRight: // <length> | <percentage> | auto | inherit @@ -598,38 +572,6 @@ CSSPropertyWebkitMaskPosition, CSSPropertyWebkitMaskOrigin, CSSPropertyWebkitMaskClip, CSSPropertyWebkitMaskSize }; return parseFillShorthand(propertyID, properties, WTF_ARRAY_LENGTH(properties), important); } - case CSSPropertyBorder: - // [ 'border-width' || 'border-style' || <color> ] - { - if (parseShorthand(propertyID, borderShorthandForParsing(), important)) { - // The CSS3 Borders and Backgrounds specification says that border also resets border-image. It's as - // though a value of none was specified for the image. - addExpandedPropertyForValue(CSSPropertyBorderImage, cssValuePool().createImplicitInitialValue(), important); - return true; - } - return false; - } - case CSSPropertyBorderTop: - // [ 'border-top-width' || 'border-style' || <color> ] - return parseShorthand(propertyID, borderTopShorthand(), important); - case CSSPropertyBorderRight: - // [ 'border-right-width' || 'border-style' || <color> ] - return parseShorthand(propertyID, borderRightShorthand(), important); - case CSSPropertyBorderBottom: - // [ 'border-bottom-width' || 'border-style' || <color> ] - return parseShorthand(propertyID, borderBottomShorthand(), important); - case CSSPropertyBorderLeft: - // [ 'border-left-width' || 'border-style' || <color> ] - return parseShorthand(propertyID, borderLeftShorthand(), important); - case CSSPropertyBorderColor: - // <color>{1,4} - return parse4Values(propertyID, borderColorShorthand().properties(), important); - case CSSPropertyBorderWidth: - // <border-width>{1,4} - return parse4Values(propertyID, borderWidthShorthand().properties(), important); - case CSSPropertyBorderStyle: - // <border-style>{1,4} - return parse4Values(propertyID, borderStyleShorthand().properties(), important); // The remaining shorthands are handled in CSSPropertyParser.cpp default: @@ -819,118 +761,6 @@ return true; } -bool CSSPropertyParser::parseShorthand(CSSPropertyID propId, const StylePropertyShorthand& shorthand, bool important) -{ - // We try to match as many properties as possible - // We set up an array of booleans to mark which property has been found, - // and we try to search for properties until it makes no longer any sense. - ShorthandScope scope(this, propId); - - bool found = false; - unsigned propertiesParsed = 0; - bool propertyFound[6] = { false, false, false, false, false, false }; // 6 is enough size. - - while (m_valueList->current()) { - found = false; - for (unsigned propIndex = 0; !found && propIndex < shorthand.length(); ++propIndex) { - if (propertyFound[propIndex]) - continue; - if (propId == CSSPropertyBorder) { - if (!legacyParseShorthand(shorthand.properties()[propIndex], important)) - continue; - } else { - if (!legacyParseAndApplyValue(shorthand.properties()[propIndex], important)) - continue; - } - propertyFound[propIndex] = found = true; - propertiesParsed++; - } - - // if we didn't find at least one match, this is an - // invalid shorthand and we have to ignore it - if (!found) - return false; - } - - if (propertiesParsed == shorthand.length()) - return true; - - // Fill in any remaining properties with the initial value. - ImplicitScope implicitScope(this); - const StylePropertyShorthand* const* const propertiesForInitialization = shorthand.propertiesForInitialization(); - for (unsigned i = 0; i < shorthand.length(); ++i) { - if (propertyFound[i]) - continue; - - if (propertiesForInitialization) { - const StylePropertyShorthand& initProperties = *(propertiesForInitialization[i]); - for (unsigned propIndex = 0; propIndex < initProperties.length(); ++propIndex) - addProperty(initProperties.properties()[propIndex], cssValuePool().createImplicitInitialValue(), important); - } else - addProperty(shorthand.properties()[i], cssValuePool().createImplicitInitialValue(), important); - } - - return true; -} - -bool CSSPropertyParser::parse4Values(CSSPropertyID propId, const CSSPropertyID *properties, bool important) -{ - /* From the CSS 2 specs, 8.3 - * If there is only one value, it applies to all sides. If there are two values, the top and - * bottom margins are set to the first value and the right and left margins are set to the second. - * If there are three values, the top is set to the first value, the left and right are set to the - * second, and the bottom is set to the third. If there are four values, they apply to the top, - * right, bottom, and left, respectively. - */ - - int num = inShorthand() ? 1 : m_valueList->size(); - - ShorthandScope scope(this, propId); - - // the order is top, right, bottom, left - switch (num) { - case 1: { - if (!legacyParseAndApplyValue(properties[0], important)) - return false; - CSSValue* value = m_parsedProperties.last().value(); - ImplicitScope implicitScope(this); - addProperty(properties[1], value, important); - addProperty(properties[2], value, important); - addProperty(properties[3], value, important); - break; - } - case 2: { - if (!legacyParseAndApplyValue(properties[0], important) || !legacyParseAndApplyValue(properties[1], important)) - return false; - CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - ImplicitScope implicitScope(this); - addProperty(properties[2], value, important); - value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - addProperty(properties[3], value, important); - break; - } - case 3: { - if (!legacyParseAndApplyValue(properties[0], important) || !legacyParseAndApplyValue(properties[1], important) || !legacyParseAndApplyValue(properties[2], important)) - return false; - CSSValue* value = m_parsedProperties[m_parsedProperties.size() - 2].value(); - ImplicitScope implicitScope(this); - addProperty(properties[3], value, important); - break; - } - case 4: { - if (!legacyParseAndApplyValue(properties[0], important) || !legacyParseAndApplyValue(properties[1], important) || - !legacyParseAndApplyValue(properties[2], important) || !legacyParseAndApplyValue(properties[3], important)) - return false; - break; - } - default: { - return false; - } - } - - return true; -} - PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseColor(const CSSParserValue* value, bool acceptQuirkyColors) { CSSValueID id = value->id; @@ -1872,7 +1702,7 @@ bool CSSPropertyParser::parseGridShorthand(bool important) { ShorthandScope scope(this, CSSPropertyGrid); - ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 6); + ASSERT(shorthandForProperty(CSSPropertyGrid).length() == 8); // 1- <grid-template> if (parseGridTemplateShorthand(important)) { @@ -1881,6 +1711,8 @@ addProperty(CSSPropertyGridAutoFlow, cssValuePool().createImplicitInitialValue(), important); addProperty(CSSPropertyGridAutoColumns, cssValuePool().createImplicitInitialValue(), important); addProperty(CSSPropertyGridAutoRows, cssValuePool().createImplicitInitialValue(), important); + addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important); + addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important); return true; } @@ -1925,6 +1757,8 @@ addProperty(CSSPropertyGridTemplateColumns, cssValuePool().createImplicitInitialValue(), important); addProperty(CSSPropertyGridTemplateRows, cssValuePool().createImplicitInitialValue(), important); addProperty(CSSPropertyGridTemplateAreas, cssValuePool().createImplicitInitialValue(), important); + addProperty(CSSPropertyGridColumnGap, cssValuePool().createImplicitInitialValue(), important); + addProperty(CSSPropertyGridRowGap, cssValuePool().createImplicitInitialValue(), important); return true; }
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index 2ee12572..588fdcb 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -1097,12 +1097,12 @@ if (!layoutObject()) return; - if (computedStyle()->affectedByFocus() && computedStyle()->hasPseudoStyle(FIRST_LETTER)) - setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); - else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus()) + if (computedStyle()->affectedByFocus()) { + StyleChangeType changeType = computedStyle()->hasPseudoStyle(FIRST_LETTER) ? SubtreeStyleChange : LocalStyleChange; + setNeedsStyleRecalc(changeType, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); + } + if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByFocus()) toElement(this)->pseudoStateChanged(CSSSelector::PseudoFocus); - else if (computedStyle()->affectedByFocus()) - setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Focus)); LayoutTheme::theme().controlStateChanged(*layoutObject(), FocusControlState); } @@ -1150,12 +1150,12 @@ // FIXME: Why does this not need to handle the display: none transition like :hover does? if (layoutObject()) { - if (computedStyle()->affectedByActive() && computedStyle()->hasPseudoStyle(FIRST_LETTER)) - setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active)); - else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByActive()) + if (computedStyle()->affectedByActive()) { + StyleChangeType changeType = computedStyle()->hasPseudoStyle(FIRST_LETTER) ? SubtreeStyleChange : LocalStyleChange; + setNeedsStyleRecalc(changeType, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active)); + } + if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByActive()) toElement(this)->pseudoStateChanged(CSSSelector::PseudoActive); - else if (computedStyle()->affectedByActive()) - setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Active)); LayoutTheme::theme().controlStateChanged(*layoutObject(), PressedControlState); } @@ -1179,12 +1179,12 @@ return; } - if (computedStyle()->affectedByHover() && computedStyle()->hasPseudoStyle(FIRST_LETTER)) - setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover)); - else if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover()) + if (computedStyle()->affectedByHover()) { + StyleChangeType changeType = computedStyle()->hasPseudoStyle(FIRST_LETTER) ? SubtreeStyleChange : LocalStyleChange; + setNeedsStyleRecalc(changeType, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover)); + } + if (isElementNode() && toElement(this)->childrenOrSiblingsAffectedByHover()) toElement(this)->pseudoStateChanged(CSSSelector::PseudoHover); - else if (computedStyle()->affectedByHover()) - setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::createWithExtraData(StyleChangeReason::PseudoClass, StyleChangeExtraData::Hover)); LayoutTheme::theme().controlStateChanged(*layoutObject(), HoverControlState); } @@ -1317,9 +1317,6 @@ ASSERT(change >= UpdatePseudoElements || childNeedsStyleRecalc()); ASSERT(!needsStyleRecalc()); - if (change < Force && hasRareData() && childNeedsStyleRecalc()) - checkForChildrenAdjacentRuleChanges(); - // This loop is deliberately backwards because we use insertBefore in the layout tree, and want to avoid // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last // child and work our way back means in the common case, we'll find the insertion point in O(1) time. @@ -1342,33 +1339,6 @@ } } -void ContainerNode::checkForChildrenAdjacentRuleChanges() -{ - bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules(); - bool hasIndirectAdjacentRules = childrenAffectedByIndirectAdjacentRules(); - - if (!hasDirectAdjacentRules && !hasIndirectAdjacentRules) - return; - - unsigned forceCheckOfNextElementCount = 0; - bool forceCheckOfAnyElementSibling = false; - Document& document = this->document(); - - for (Element* child = ElementTraversal::firstChild(*this); child; child = ElementTraversal::nextSibling(*child)) { - bool childRulesChanged = child->needsStyleRecalc() && child->styleChangeType() >= SubtreeStyleChange; - - if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling) - child->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); - - if (childRulesChanged && hasDirectAdjacentRules) - forceCheckOfNextElementCount = document.styleEngine().maxDirectAdjacentSelectors(); - else if (forceCheckOfNextElementCount) - --forceCheckOfNextElementCount; - - forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules); - } -} - void ContainerNode::checkForSiblingStyleChanges(SiblingCheckType changeType, Node* nodeBeforeChange, Node* nodeAfterChange) { if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || styleChangeType() >= SubtreeStyleChange) @@ -1434,7 +1404,8 @@ // The + selector. We need to invalidate the first element following the change. It is the only possible element // that could be affected by this DOM change. if (childrenAffectedByDirectAdjacentRules() && nodeAfterChange) { - if (Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange)) + Element* elementAfterChange = nodeAfterChange->isElementNode() ? toElement(nodeAfterChange) : ElementTraversal::nextSibling(*nodeAfterChange); + for (unsigned i = document().styleEngine().maxDirectAdjacentSelectors(); i && elementAfterChange; --i, elementAfterChange = ElementTraversal::nextSibling(*elementAfterChange)) elementAfterChange->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SiblingSelector)); } }
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.h b/third_party/WebKit/Source/core/dom/ContainerNode.h index b8193590..02159ca 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.h +++ b/third_party/WebKit/Source/core/dom/ContainerNode.h
@@ -160,7 +160,6 @@ // FIXME: These methods should all be renamed to something better than "check", // since it's not clear that they alter the style bits of siblings and children. - void checkForChildrenAdjacentRuleChanges(); enum SiblingCheckType { FinishedParsingChildren, SiblingElementInserted, SiblingElementRemoved }; void checkForSiblingStyleChanges(SiblingCheckType, Node* nodeBeforeChange, Node* nodeAfterChange); void recalcChildStyle(StyleRecalcChange);
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index 303f98e0..d5f65bbc 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4160,7 +4160,9 @@ currentDocument = currentDocument->parentDocument(); ASSERT(currentDocument); - if (accessEntry.matchesOrigin(*currentDocument->securityOrigin()) == OriginAccessEntry::DoesNotMatchOrigin) + // We use 'matchesDomain' here, as it turns out that some folks embed HTTPS login forms + // into HTTP pages; we should allow this kind of upgrade. + if (accessEntry.matchesDomain(*currentDocument->securityOrigin()) == OriginAccessEntry::DoesNotMatchOrigin) return SecurityOrigin::urlWithUniqueSecurityOrigin(); currentDocument = currentDocument->parentDocument();
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index c9099642..3a09355 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1636,7 +1636,8 @@ document().userActionElements().didDetach(*this); } - document().styleEngine().styleInvalidator().clearInvalidation(*this); + if (context.clearInvalidation) + document().styleEngine().styleInvalidator().clearInvalidation(*this); if (svgFilterNeedsLayerUpdate()) document().unscheduleSVGFilterLayerUpdateHack(*this);
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp index 1f06da2f..a32edd7 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObservation.cpp
@@ -161,9 +161,15 @@ void IntersectionObservation::disconnect() { + IntersectionObserver* observer = m_observer; + clearRootAndRemoveFromTarget(); + observer->removeObservation(*this); +} + +void IntersectionObservation::clearRootAndRemoveFromTarget() +{ if (m_target) - target()->ensureIntersectionObserverData().removeObservation(this->observer()); - m_observer->removeObservation(*this); + target()->ensureIntersectionObserverData().removeObservation(observer()); m_observer.clear(); }
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObservation.h b/third_party/WebKit/Source/core/dom/IntersectionObservation.h index 7299922f..9388af9 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObservation.h +++ b/third_party/WebKit/Source/core/dom/IntersectionObservation.h
@@ -32,9 +32,9 @@ unsigned lastThresholdIndex() const { return m_lastThresholdIndex; } void setLastThresholdIndex(unsigned index) { m_lastThresholdIndex = index; } bool shouldReportRootBounds() const { return m_shouldReportRootBounds; } - void computeIntersectionObservations(double timestamp); void disconnect(); + void clearRootAndRemoveFromTarget(); DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp index b29b69e8..efe97c9 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp +++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.cpp
@@ -152,6 +152,16 @@ root.document().ensureIntersectionObserverController().addTrackedObserver(*this); } +#if ENABLE(OILPAN) +void IntersectionObserver::clearWeakMembers(Visitor* visitor) +{ + if (Heap::isHeapObjectAlive(m_root)) + return; + disconnect(); + m_root = nullptr; +} +#endif + LayoutObject* IntersectionObserver::rootLayoutObject() const { Node* rootNode = root(); @@ -186,7 +196,6 @@ void IntersectionObserver::observe(Element* target, ExceptionState& exceptionState) { - checkRootAndDetachIfNeeded(); if (!m_root) { exceptionState.throwDOMException(HierarchyRequestError, "Invalid observer: root element or containing document has been deleted."); return; @@ -221,7 +230,6 @@ void IntersectionObserver::unobserve(Element* target, ExceptionState&) { - checkRootAndDetachIfNeeded(); if (!target || !target->intersectionObserverData()) return; // TODO(szager): unobserve callback @@ -231,7 +239,6 @@ void IntersectionObserver::computeIntersectionObservations(double timestamp) { - checkRootAndDetachIfNeeded(); if (!m_root) return; for (auto& observation : m_observations) @@ -240,11 +247,9 @@ void IntersectionObserver::disconnect() { - HeapVector<Member<IntersectionObservation>> observationsToDisconnect; - copyToVector(m_observations, observationsToDisconnect); - for (auto& observation : observationsToDisconnect) - observation->disconnect(); - ASSERT(m_observations.isEmpty()); + for (auto& observation : m_observations) + observation->clearRootAndRemoveFromTarget(); + m_observations.clear(); } void IntersectionObserver::removeObservation(IntersectionObservation& observation) @@ -254,7 +259,6 @@ HeapVector<Member<IntersectionObserverEntry>> IntersectionObserver::takeRecords() { - checkRootAndDetachIfNeeded(); HeapVector<Member<IntersectionObserverEntry>> entries; entries.swap(m_entries); return entries; @@ -299,7 +303,6 @@ void IntersectionObserver::deliver() { - checkRootAndDetachIfNeeded(); if (m_entries.isEmpty()) return; @@ -311,7 +314,6 @@ void IntersectionObserver::setActive(bool active) { - checkRootAndDetachIfNeeded(); for (auto& observation : m_observations) observation->setActive(m_root && active && isDescendantOfRoot(observation->target())); } @@ -324,27 +326,12 @@ || m_leftMargin.type() == Percent); } -void IntersectionObserver::checkRootAndDetachIfNeeded() -{ -#if ENABLE(OILPAN) - // TODO(szager): Pre-oilpan, ElementIntersectionObserverData::dispose() will take - // care of this cleanup. When oilpan ships, there will be a potential leak of the - // callback's execution context when the root goes away. For a detailed explanation: - // - // https://goo.gl/PC2Baj - // - // When that happens, this method should catch most potential leaks, but a complete - // solution will still be needed, along the lines described in the above link. - if (m_root) - return; - disconnect(); -#endif -} - DEFINE_TRACE(IntersectionObserver) { +#if ENABLE(OILPAN) + visitor->template registerWeakMembers<IntersectionObserver, &IntersectionObserver::clearWeakMembers>(this); +#endif visitor->trace(m_callback); - visitor->trace(m_root); visitor->trace(m_observations); visitor->trace(m_entries); }
diff --git a/third_party/WebKit/Source/core/dom/IntersectionObserver.h b/third_party/WebKit/Source/core/dom/IntersectionObserver.h index f793a6f..d3e61cd9 100644 --- a/third_party/WebKit/Source/core/dom/IntersectionObserver.h +++ b/third_party/WebKit/Source/core/dom/IntersectionObserver.h
@@ -55,8 +55,9 @@ private: explicit IntersectionObserver(IntersectionObserverCallback&, Node&, const Vector<Length>& rootMargin, const Vector<float>& thresholds); - - void checkRootAndDetachIfNeeded(); +#if ENABLE(OILPAN) + void clearWeakMembers(Visitor*); +#endif Member<IntersectionObserverCallback> m_callback; WeakPtrWillBeWeakMember<Node> m_root;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index 7d05c511..344f364 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -577,7 +577,7 @@ return toDataURLInternal(mimeType, quality, BackBuffer); } -void HTMLCanvasElement::toBlob(FileCallback* callback, const String& mimeType, const ScriptValue& qualityArgument, ExceptionState& exceptionState) +void HTMLCanvasElement::toBlob(ScriptState* scriptState, FileCallback* callback, const String& mimeType, const ScriptValue& qualityArgument, ExceptionState& exceptionState) { if (!originClean()) { exceptionState.throwSecurityError("Tainted canvases may not be exported."); @@ -606,7 +606,7 @@ // Add a ref to keep image data alive until completion of encoding RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); - RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::create(imageDataRef.release(), encodingMimeType, imageData->size(), callback); + RefPtr<CanvasAsyncBlobCreator> asyncCreatorRef = CanvasAsyncBlobCreator::create(imageDataRef.release(), encodingMimeType, imageData->size(), callback, scriptState->executionContext()); // TODO(xlai): Remove idle-periods version of implementation completely, http://crbug.com/564218 asyncCreatorRef->scheduleAsyncBlobCreation(false, quality);
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h index 24e646da..19e8910 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -101,8 +101,8 @@ String toDataURL(const String& mimeType, const ScriptValue& qualityArgument, ExceptionState&) const; String toDataURL(const String& mimeType, ExceptionState& exceptionState) const { return toDataURL(mimeType, ScriptValue(), exceptionState); } - void toBlob(FileCallback*, const String& mimeType, const ScriptValue& qualityArgument, ExceptionState&); - void toBlob(FileCallback* callback, const String& mimeType, ExceptionState& exceptionState) { return toBlob(callback, mimeType, ScriptValue(), exceptionState); } + void toBlob(ScriptState*, FileCallback*, const String& mimeType, const ScriptValue& qualityArgument, ExceptionState&); + void toBlob(ScriptState* scriptState, FileCallback* callback, const String& mimeType, ExceptionState& exceptionState) { return toBlob(scriptState, callback, mimeType, ScriptValue(), exceptionState); } // Used for canvas capture. void addListener(CanvasDrawListener*);
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.idl b/third_party/WebKit/Source/core/html/HTMLCanvasElement.idl index 393bb2a..c4b18d5 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.idl +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.idl
@@ -53,5 +53,5 @@ // FIXME: type should not have a default value. [RaisesException] DOMString toDataURL(optional DOMString type = null, optional any arguments); - [RaisesException, RuntimeEnabled=ExperimentalCanvasFeatures] void toBlob(FileCallback _callback, optional DOMString type = null, optional any arguments); + [RaisesException, CallWith=ScriptState, RuntimeEnabled=ExperimentalCanvasFeatures] void toBlob(FileCallback _callback, optional DOMString type = null, optional any arguments); };
diff --git a/third_party/WebKit/Source/core/html/HTMLContentElement.cpp b/third_party/WebKit/Source/core/html/HTMLContentElement.cpp index 36d42a5..77e434d 100644 --- a/third_party/WebKit/Source/core/html/HTMLContentElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLContentElement.cpp
@@ -75,8 +75,10 @@ void HTMLContentElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value) { if (name == selectAttr) { - if (ShadowRoot* root = containingShadowRoot()) - root->owner()->willAffectSelector(); + if (ShadowRoot* root = containingShadowRoot()) { + if (root->owner()) + root->owner()->willAffectSelector(); + } m_shouldParseSelect = true; m_select = value; } else {
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp index 4158ea9..9e31b6a 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.cpp
@@ -4,10 +4,12 @@ #include "CanvasAsyncBlobCreator.h" +#include "core/dom/ContextLifecycleObserver.h" #include "core/fileapi/File.h" #include "platform/Task.h" #include "platform/ThreadSafeFunctional.h" #include "platform/graphics/ImageBuffer.h" +#include "platform/heap/Handle.h" #include "platform/image-encoders/skia/PNGImageEncoder.h" #include "public/platform/Platform.h" #include "public/platform/WebScheduler.h" @@ -30,13 +32,51 @@ } // anonymous namespace -PassRefPtr<CanvasAsyncBlobCreator> CanvasAsyncBlobCreator::create(PassRefPtr<DOMUint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const IntSize& size, FileCallback* callback) +class CanvasAsyncBlobCreator::ContextObserver final : public NoBaseWillBeGarbageCollected<CanvasAsyncBlobCreator::ContextObserver>, public ContextLifecycleObserver { + WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(CanvasAsyncBlobCreator::ContextObserver); +public: + ContextObserver(ExecutionContext* executionContext, CanvasAsyncBlobCreator* asyncBlobCreator) + : ContextLifecycleObserver(executionContext) + , m_asyncBlobCreator(asyncBlobCreator) + { + } + + DECLARE_VIRTUAL_TRACE(); + + void contextDestroyed() override + { + ContextLifecycleObserver::contextDestroyed(); + if (!!m_asyncBlobCreator) { + m_asyncBlobCreator->m_cancelled = true; + // After sending cancel signal to asyncBlobCreator, the observer has + // done its job and thus deref asyncBlobCreator for proper destruction + m_asyncBlobCreator = nullptr; + } + } + + void dispose() + { + // In Oilpan context, on-heap ContextObserver sometimes live longer than + // off-heap CanvasAsyncBlobCreator, thus we need to dispose backref to + // m_asyncBlobCreator here when its destructor is called to avoid + // heap-use-after-free error. + m_asyncBlobCreator = nullptr; + } + +private: + CanvasAsyncBlobCreator* m_asyncBlobCreator; +}; + +PassRefPtr<CanvasAsyncBlobCreator> CanvasAsyncBlobCreator::create(PassRefPtr<DOMUint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const IntSize& size, FileCallback* callback, ExecutionContext* executionContext) { - return adoptRef(new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, mimeType, size, callback)); + RefPtr<CanvasAsyncBlobCreator> asyncBlobCreator = adoptRef(new CanvasAsyncBlobCreator(unpremultipliedRGBAImageData, mimeType, size, callback)); + asyncBlobCreator->createContextObserver(executionContext); + return asyncBlobCreator.release(); } CanvasAsyncBlobCreator::CanvasAsyncBlobCreator(PassRefPtr<DOMUint8ClampedArray> data, const String& mimeType, const IntSize& size, FileCallback* callback) - : m_data(data) + : m_cancelled(false) + , m_data(data) , m_size(size) , m_mimeType(mimeType) , m_callback(callback) @@ -47,7 +87,16 @@ m_numRowsCompleted = 0; } -CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() { } +CanvasAsyncBlobCreator::~CanvasAsyncBlobCreator() +{ + if (!!m_contextObserver) + m_contextObserver->dispose(); +} + +DEFINE_TRACE(CanvasAsyncBlobCreator::ContextObserver) +{ + ContextLifecycleObserver::trace(visitor); +} void CanvasAsyncBlobCreator::scheduleAsyncBlobCreation(bool canUseIdlePeriodScheduling, double quality) { @@ -61,7 +110,7 @@ ASSERT(m_mimeType == "image/png"); Platform::current()->mainThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind<double>(&CanvasAsyncBlobCreator::initiatePngEncoding, this)); } else { - getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&CanvasAsyncBlobCreator::encodeImageOnAsyncThread, AllowCrossThreadAccess(this), quality))); + getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new Task(threadSafeBind(&CanvasAsyncBlobCreator::encodeImageOnEncoderThread, AllowCrossThreadAccess(this), quality))); } } @@ -108,20 +157,74 @@ { File* resultBlob = File::create(m_encodedImage->data(), m_encodedImage->size(), m_mimeType); Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, bind(&FileCallback::handleEvent, m_callback, resultBlob)); - m_selfRef.clear(); // self-destruct once job is done. + clearSelfReference(); // self-destruct once job is done. } -void CanvasAsyncBlobCreator::encodeImageOnAsyncThread(double quality) +void CanvasAsyncBlobCreator::encodeImageOnEncoderThread(double quality) { ASSERT(!isMainThread()); - - if (!ImageDataBuffer(m_size, m_data->data()).encodeImage(m_mimeType, quality, m_encodedImage.get())) { - Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, bind(&FileCallback::handleEvent, m_callback, nullptr)); - } else { - Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThreadAccess(this))); + if (initializeEncodeImageOnEncoderThread()) { + if (m_mimeType == "image/png") { + // At the time being, progressive encoding is only applicable to png image format + // TODO(xlai): Progressive encoding on jpeg and webp image formats (crbug.com/571398, crbug.com/571399) + progressiveEncodeImageOnEncoderThread(); + } else { + nonprogressiveEncodeImageOnEncoderThread(quality); + } } } +bool CanvasAsyncBlobCreator::initializeEncodeImageOnEncoderThread() +{ + if (m_cancelled) { + scheduleClearSelfRefOnMainThread(); + return false; + } + + if (m_mimeType == "image/png") { + m_encoderState = PNGImageEncoderState::create(m_size, m_encodedImage.get()); + if (m_cancelled) { + scheduleClearSelfRefOnMainThread(); + return false; + } + if (!m_encoderState) { + scheduleCreateNullptrAndCallOnMainThread(); + return false; + } + } // else, do nothing; as encoding on other image formats are not progressive + return true; +} + +void CanvasAsyncBlobCreator::nonprogressiveEncodeImageOnEncoderThread(double quality) +{ + if (ImageDataBuffer(m_size, m_data->data()).encodeImage(m_mimeType, quality, m_encodedImage.get())) { + scheduleCreateBlobAndCallOnMainThread(); + } else { + scheduleCreateNullptrAndCallOnMainThread(); + } +} + +void CanvasAsyncBlobCreator::progressiveEncodeImageOnEncoderThread() +{ + unsigned char* inputPixels = m_data->data() + m_pixelRowStride * m_numRowsCompleted; + for (int y = 0; y < m_size.height() && !m_cancelled; ++y) { + PNGImageEncoder::writeOneRowToPng(inputPixels, m_encoderState.get()); + inputPixels += m_pixelRowStride; + } + if (m_cancelled) { + scheduleClearSelfRefOnMainThread(); + return; + } + + PNGImageEncoder::finalizePng(m_encoderState.get()); + if (m_cancelled) { + scheduleClearSelfRefOnMainThread(); + return; + } + + scheduleCreateBlobAndCallOnMainThread(); +} + WebThread* CanvasAsyncBlobCreator::getToBlobThreadInstance() { DEFINE_STATIC_LOCAL(OwnPtr<WebThread>, s_toBlobThread, ()); @@ -131,4 +234,33 @@ return s_toBlobThread.get(); } +void CanvasAsyncBlobCreator::createContextObserver(ExecutionContext* executionContext) +{ + m_contextObserver = adoptPtrWillBeNoop(new ContextObserver(executionContext, this)); +} + +void CanvasAsyncBlobCreator::clearSelfReference() +{ + // Some persistent members in CanvasAsyncBlobCreator can only be destroyed + // on the thread that creates them. In this case, it's the main thread. + ASSERT(isMainThread()); + m_selfRef.clear(); +} + +void CanvasAsyncBlobCreator::scheduleClearSelfRefOnMainThread() +{ + Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CanvasAsyncBlobCreator::clearSelfReference, AllowCrossThreadAccess(this))); +} + +void CanvasAsyncBlobCreator::scheduleCreateBlobAndCallOnMainThread() +{ + Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CanvasAsyncBlobCreator::createBlobAndCall, AllowCrossThreadAccess(this))); +} + +void CanvasAsyncBlobCreator::scheduleCreateNullptrAndCallOnMainThread() +{ + Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, bind(&FileCallback::handleEvent, m_callback, nullptr)); + Platform::current()->mainThread()->taskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CanvasAsyncBlobCreator::clearSelfReference, AllowCrossThreadAccess(this))); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h index 410db197..f48fe7b 100644 --- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
@@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "core/CoreExport.h" #include "core/dom/DOMTypedArray.h" +#include "core/dom/ExecutionContext.h" #include "core/fileapi/FileCallback.h" #include "platform/geometry/IntSize.h" #include "platform/heap/Handle.h" @@ -16,15 +18,23 @@ class PNGImageEncoderState; -class CanvasAsyncBlobCreator final : public ThreadSafeRefCounted<CanvasAsyncBlobCreator> { +class CORE_EXPORT CanvasAsyncBlobCreator + : public RefCounted<CanvasAsyncBlobCreator> { public: - static PassRefPtr<CanvasAsyncBlobCreator> create(PassRefPtr<DOMUint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const IntSize&, FileCallback*); + static PassRefPtr<CanvasAsyncBlobCreator> create(PassRefPtr<DOMUint8ClampedArray> unpremultipliedRGBAImageData, const String& mimeType, const IntSize&, FileCallback*, ExecutionContext*); void scheduleAsyncBlobCreation(bool canUseIdlePeriodScheduling, double quality = 0.0); static WebThread* getToBlobThreadInstance(); virtual ~CanvasAsyncBlobCreator(); -private: +protected: CanvasAsyncBlobCreator(PassRefPtr<DOMUint8ClampedArray> data, const String& mimeType, const IntSize&, FileCallback*); + virtual void scheduleCreateBlobAndCallOnMainThread(); + virtual void scheduleCreateNullptrAndCallOnMainThread(); + virtual void scheduleClearSelfRefOnMainThread(); + std::atomic<bool> m_cancelled; + +private: + friend class CanvasAsyncBlobCreatorTest; OwnPtr<PNGImageEncoderState> m_encoderState; RefPtr<DOMUint8ClampedArray> m_data; @@ -37,13 +47,22 @@ Persistent<FileCallback> m_callback; RefPtr<CanvasAsyncBlobCreator> m_selfRef; + void clearSelfReference(); void initiatePngEncoding(double deadlineSeconds); void scheduleIdleEncodeRowsPng(); void idleEncodeRowsPng(double deadlineSeconds); + void createBlobAndCall(); - void encodeImageOnAsyncThread(double quality); + void encodeImageOnEncoderThread(double quality); + bool initializeEncodeImageOnEncoderThread(); + void nonprogressiveEncodeImageOnEncoderThread(double quality); + void progressiveEncodeImageOnEncoderThread(); + + class ContextObserver; + void createContextObserver(ExecutionContext*); + OwnPtrWillBePersistent<ContextObserver> m_contextObserver; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp new file mode 100644 index 0000000..8518283 --- /dev/null +++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreatorTest.cpp
@@ -0,0 +1,193 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "core/html/canvas/CanvasAsyncBlobCreator.h" + +#include "core/html/ImageData.h" +#include "public/platform/Platform.h" +#include "public/platform/WebWaitableEvent.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blink { + +class MockCanvasAsyncBlobCreator; + +class FakeContextObserver { +public: + FakeContextObserver(MockCanvasAsyncBlobCreator* asyncBlobCreator) + : m_asyncBlobCreator(asyncBlobCreator) + { + } + + void contextDestroyed(); + +private: + MockCanvasAsyncBlobCreator* m_asyncBlobCreator; +}; + +//============================================================================ + +class MockCanvasAsyncBlobCreator : public CanvasAsyncBlobCreator { +public: + MockCanvasAsyncBlobCreator(PassRefPtr<DOMUint8ClampedArray> data, const String& mimeType, const IntSize& size) + : CanvasAsyncBlobCreator(data, mimeType, size, nullptr) + { + } + + void setFakeContextObserver(FakeContextObserver* contextObserver) + { + m_contextObserver = contextObserver; + } + + bool isCancelled() { return m_cancelled; } + void onContextDestroyed() + { + m_cancelled = true; + } + MOCK_METHOD0(scheduleClearSelfRefOnMainThread, void()); + MOCK_METHOD0(scheduleCreateNullptrAndCallOnMainThread, void()); + MOCK_METHOD0(scheduleCreateBlobAndCallOnMainThread, void()); + +private: + FakeContextObserver* m_contextObserver; +}; + +//============================================================================ + +class CanvasAsyncBlobCreatorTest : public ::testing::Test { +public: + void prepareMockCanvasAsyncBlobCreator(int width, int height); + bool initializeEncodeImage() { return m_asyncBlobCreator->initializeEncodeImageOnEncoderThread(); } + void startEncodeImage() { m_asyncBlobCreator->progressiveEncodeImageOnEncoderThread(); } + +protected: + CanvasAsyncBlobCreatorTest(); + void TearDown() override; + MockCanvasAsyncBlobCreator* asyncBlobCreator(); + FakeContextObserver* contextObserver(); + +private: + RefPtr<MockCanvasAsyncBlobCreator> m_asyncBlobCreator; + FakeContextObserver* m_contextObserver; +}; + +//============================================================================ + +class ImageEncodingTask : public WebTaskRunner::Task { +public: + ImageEncodingTask(CanvasAsyncBlobCreatorTest* testHost, WebWaitableEvent* startEvent, WebWaitableEvent* doneEvent) + : m_testHost(testHost) + , m_startEvent(startEvent) + , m_doneEvent(doneEvent) + { + } + + virtual ~ImageEncodingTask() { } + + void run() override + { + bool initializationSuccess = m_testHost->initializeEncodeImage(); + if (!!m_startEvent) + m_startEvent->signal(); + if (initializationSuccess) + m_testHost->startEncodeImage(); + m_doneEvent->signal(); + } + +private: + CanvasAsyncBlobCreatorTest* m_testHost; + WebWaitableEvent* m_startEvent; + WebWaitableEvent* m_doneEvent; +}; + +//============================================================================ + + +CanvasAsyncBlobCreatorTest::CanvasAsyncBlobCreatorTest() +{ +} + +void CanvasAsyncBlobCreatorTest::prepareMockCanvasAsyncBlobCreator(int width, int height) +{ + IntSize testSize(width, height); + ImageData* imageData = ImageData::create(testSize); + RefPtr<DOMUint8ClampedArray> imageDataRef(imageData->data()); + + m_asyncBlobCreator = adoptRef(new MockCanvasAsyncBlobCreator(imageDataRef.release(), "image/png", testSize)); + m_contextObserver = new FakeContextObserver(m_asyncBlobCreator.get()); + m_asyncBlobCreator->setFakeContextObserver(m_contextObserver); +} + +void CanvasAsyncBlobCreatorTest::TearDown() +{ + delete m_contextObserver; + m_asyncBlobCreator->m_selfRef.clear(); +} + +void FakeContextObserver::contextDestroyed() +{ + m_asyncBlobCreator->onContextDestroyed(); + m_asyncBlobCreator = nullptr; +} + +MockCanvasAsyncBlobCreator* CanvasAsyncBlobCreatorTest::asyncBlobCreator() +{ + return m_asyncBlobCreator.get(); +} + +FakeContextObserver* CanvasAsyncBlobCreatorTest::contextObserver() +{ + return m_contextObserver; +} + +TEST_F(CanvasAsyncBlobCreatorTest, CancelImageEncodingWhenContextTornDown) +{ + this->prepareMockCanvasAsyncBlobCreator(4000, 4000); + + OwnPtr<WebWaitableEvent> startEvent = adoptPtr(Platform::current()->createWaitableEvent()); + OwnPtr<WebWaitableEvent> doneEvent = adoptPtr(Platform::current()->createWaitableEvent()); + + EXPECT_CALL(*(asyncBlobCreator()), scheduleClearSelfRefOnMainThread()); + + CanvasAsyncBlobCreator::getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new ImageEncodingTask(this, startEvent.get(), doneEvent.get())); + startEvent->wait(); + contextObserver()->contextDestroyed(); + doneEvent->wait(); + + ::testing::Mock::VerifyAndClearExpectations(asyncBlobCreator()); + EXPECT_TRUE(asyncBlobCreator()->isCancelled()); +} + +TEST_F(CanvasAsyncBlobCreatorTest, CompleteImageEncodingWithoutContextTornDown) +{ + this->prepareMockCanvasAsyncBlobCreator(50, 50); + + OwnPtr<WebWaitableEvent> doneEvent = adoptPtr(Platform::current()->createWaitableEvent()); + + EXPECT_CALL(*(asyncBlobCreator()), scheduleCreateBlobAndCallOnMainThread()); + + CanvasAsyncBlobCreator::getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new ImageEncodingTask(this, nullptr, doneEvent.get())); + doneEvent->wait(); + + ::testing::Mock::VerifyAndClearExpectations(asyncBlobCreator()); + EXPECT_FALSE(asyncBlobCreator()->isCancelled()); +} + +TEST_F(CanvasAsyncBlobCreatorTest, FailedImageEncodingOnEmptyImageData) +{ + this->prepareMockCanvasAsyncBlobCreator(0, 0); + + OwnPtr<WebWaitableEvent> doneEvent = adoptPtr(Platform::current()->createWaitableEvent()); + + EXPECT_CALL(*(asyncBlobCreator()), scheduleCreateNullptrAndCallOnMainThread()); + + CanvasAsyncBlobCreator::getToBlobThreadInstance()->taskRunner()->postTask(BLINK_FROM_HERE, new ImageEncodingTask(this, nullptr, doneEvent.get())); + doneEvent->wait(); + + ::testing::Mock::VerifyAndClearExpectations(asyncBlobCreator()); + EXPECT_FALSE(asyncBlobCreator()->isCancelled()); +} + +} // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index f064c61..8caf559 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -2221,16 +2221,21 @@ return false; } -// TODO (lajava) can/should move this inside specific layout classes (flex. grid) ? Can we reactoring columnFlexItemHasStretchAlignment logic ? +// TODO (lajava) Can/Should we move this inside specific layout classes (flex. grid)? Can we refactor columnFlexItemHasStretchAlignment logic? bool LayoutBox::hasStretchedLogicalWidth() const { + auto& style = styleRef(); + if (!style.logicalWidth().isAuto() || style.marginStart().isAuto() || style.marginEnd().isAuto()) + return false; LayoutBlock* cb = containingBlock(); - const ComputedStyle& style = styleRef(); - bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode(); - bool allowedToStretch = style.logicalWidth().isAuto() && !style.marginStart().isAuto() && !style.marginEnd().isAuto(); - if (hasPerpendicularContainingBlock) - return allowedToStretch && ComputedStyle::resolveAlignment(cb->styleRef(), style, ItemPositionStretch) == ItemPositionStretch; - return allowedToStretch && ComputedStyle::resolveJustification(cb->styleRef(), style, ItemPositionStretch) == ItemPositionStretch; + if (!cb) { + // We are evaluating align-self/justify-self, which default to 'normal' for the root element. + // The 'normal' value behaves like 'start' except for Flexbox Items, which obviously should have a container. + return false; + } + if (cb->isHorizontalWritingMode() != isHorizontalWritingMode()) + return ComputedStyle::resolveAlignment(cb->styleRef(), style, ItemPositionStretch) == ItemPositionStretch; + return ComputedStyle::resolveJustification(cb->styleRef(), style, ItemPositionStretch) == ItemPositionStretch; } bool LayoutBox::sizesLogicalWidthToFitContent(const Length& logicalWidth) const
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp index d2c58ba6..2d8d7a8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -1486,47 +1486,48 @@ void LayoutGrid::offsetAndBreadthForPositionedChild(const LayoutBox& child, GridTrackSizingDirection direction, LayoutUnit& offset, LayoutUnit& breadth) { ASSERT(child.isHorizontalWritingMode() == isHorizontalWritingMode()); + bool isForColumns = direction == ForColumns; GridSpan positions = GridResolvedPosition::resolveGridPositionsFromStyle(*style(), child, direction); if (positions.isIndefinite()) { offset = LayoutUnit(); - breadth = (direction == ForColumns) ? clientLogicalWidth() : clientLogicalHeight(); + breadth = isForColumns ? clientLogicalWidth() : clientLogicalHeight(); return; } - positions.translate(direction == ForColumns ? m_smallestColumnStart : m_smallestRowStart); - GridPosition startPosition = (direction == ForColumns) ? child.style()->gridColumnStart() : child.style()->gridRowStart(); - GridPosition endPosition = (direction == ForColumns) ? child.style()->gridColumnEnd() : child.style()->gridRowEnd(); - size_t lastTrackIndex = (direction == ForColumns ? gridColumnCount() : gridRowCount()) - 1; + // For positioned items we cannot use GridSpan::translate(). Because we could end up with negative values, as the positioned items do not create implicit tracks per spec. + int smallestStart = abs(isForColumns ? m_smallestColumnStart : m_smallestRowStart); + int resolvedInitialPosition = positions.untranslatedResolvedInitialPosition() + smallestStart; + int resolvedFinalPosition = positions.untranslatedResolvedFinalPosition() + smallestStart; + + GridPosition startPosition = isForColumns ? child.style()->gridColumnStart() : child.style()->gridRowStart(); + GridPosition endPosition = isForColumns ? child.style()->gridColumnEnd() : child.style()->gridRowEnd(); + int lastExplicitLine = isForColumns ? gridColumnCount() : gridRowCount(); bool startIsAuto = startPosition.isAuto() || (startPosition.isNamedGridArea() && !GridResolvedPosition::isValidNamedLineOrArea(startPosition.namedGridLine(), styleRef(), GridResolvedPosition::initialPositionSide(direction))) - || (positions.resolvedInitialPosition() > lastTrackIndex); + || (resolvedInitialPosition < 0) + || (resolvedInitialPosition > lastExplicitLine); bool endIsAuto = endPosition.isAuto() || (endPosition.isNamedGridArea() && !GridResolvedPosition::isValidNamedLineOrArea(endPosition.namedGridLine(), styleRef(), GridResolvedPosition::finalPositionSide(direction))) - || (positions.resolvedFinalPosition() - 1 > lastTrackIndex); + || (resolvedFinalPosition < 0) + || (resolvedFinalPosition > lastExplicitLine); - size_t firstPosition = 0; - size_t initialPosition = startIsAuto ? firstPosition : positions.resolvedInitialPosition(); - size_t lastPosition = lastTrackIndex; - size_t finalPosition = endIsAuto ? lastPosition : positions.resolvedFinalPosition() - 1; + size_t initialPosition = startIsAuto ? 0 : resolvedInitialPosition; + size_t finalPosition = endIsAuto ? lastExplicitLine : resolvedFinalPosition; - // Positioned children do not grow the grid, so we need to clamp the positions to avoid ending up outside of it. - initialPosition = std::min(initialPosition, lastPosition); - finalPosition = std::min(finalPosition, lastPosition); - - LayoutUnit start = startIsAuto ? LayoutUnit() : (direction == ForColumns) ? m_columnPositions[initialPosition] : m_rowPositions[initialPosition]; - LayoutUnit end = endIsAuto ? (direction == ForColumns) ? logicalWidth() : logicalHeight() : (direction == ForColumns) ? m_columnPositions[finalPosition + 1] : m_rowPositions[finalPosition + 1]; + LayoutUnit start = startIsAuto ? LayoutUnit() : isForColumns ? m_columnPositions[initialPosition] : m_rowPositions[initialPosition]; + LayoutUnit end = endIsAuto ? isForColumns ? logicalWidth() : logicalHeight() : isForColumns ? m_columnPositions[finalPosition] : m_rowPositions[finalPosition]; breadth = end - start; if (startIsAuto) - breadth -= (direction == ForColumns) ? borderStart() : borderBefore(); + breadth -= isForColumns ? borderStart() : borderBefore(); else - start -= ((direction == ForColumns) ? borderStart() : borderBefore()); + start -= isForColumns ? borderStart() : borderBefore(); if (endIsAuto) { - breadth -= (direction == ForColumns) ? borderEnd() : borderAfter(); + breadth -= isForColumns ? borderEnd() : borderAfter(); breadth -= scrollbarLogicalWidth(); } @@ -1535,7 +1536,7 @@ if (child.parent() == this && !startIsAuto) { // If column/row start is "auto" the static position has been already set in prepareChildForPositionedLayout(). PaintLayer* childLayer = child.layer(); - if (direction == ForColumns) + if (isForColumns) childLayer->setStaticInlinePosition(borderStart() + offset); else childLayer->setStaticBlockPosition(borderBefore() + offset);
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js index f415bdb..ba18ffd90 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/FileSystemWorkspaceBinding.js
@@ -508,7 +508,8 @@ { var uiSourceCode = this.uiSourceCodeForURL(path); if (!uiSourceCode) { - this._addFile(path); + var contentType = WebInspector.FileSystemWorkspaceBinding._contentTypeForExtension(this._extensionForPath(path)); + this.addUISourceCode(this.createUISourceCode(path, contentType)); return; } uiSourceCode.checkContentUpdated();
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp index 17150794..4028270 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -409,10 +409,14 @@ CodePath Font::codePath(const TextRunPaintInfo& runInfo) const { +// TODO(eae): Disable the always use complex text feature on Android for now as +// it caused a memory regression for webview. crbug.com/577306 +#if !OS(ANDROID) if (RuntimeEnabledFeatures::alwaysUseComplexTextEnabled() || LayoutTestSupport::alwaysUseComplexTextForTest()) { return ComplexPath; } +#endif const TextRun& run = runInfo.run;
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp index 9536579..57f68b9 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -75,8 +75,8 @@ m_paintState = m_paintStateStack.last().get(); if (contextDisabled()) { - DEFINE_STATIC_LOCAL(RefPtr<SkCanvas>, nullCanvas, (adoptRef(SkCreateNullCanvas()))); - m_canvas = nullCanvas.get(); + DEFINE_STATIC_REF(SkCanvas, nullCanvas, (adoptRef(SkCreateNullCanvas()))); + m_canvas = nullCanvas; } }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp index 1b86c47..fd9970a 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -244,19 +244,14 @@ // Tell the derived class to scroll its contents. setScrollOffset(truncatedPosition, scrollType); - Scrollbar* verticalScrollbar = this->verticalScrollbar(); - // Tell the scrollbars to update their thumb postions. - if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) { + // If the scrollbar does not have its own layer, it must always be + // invalidated to reflect the new thumb position, even if the theme did not + // invalidate any individual part. + if (Scrollbar* horizontalScrollbar = this->horizontalScrollbar()) horizontalScrollbar->offsetDidChange(); - if (horizontalScrollbar->isOverlayScrollbar() && !hasLayerForHorizontalScrollbar()) - setScrollbarNeedsPaintInvalidation(HorizontalScrollbar); - } - if (verticalScrollbar) { + if (Scrollbar* verticalScrollbar = this->verticalScrollbar()) verticalScrollbar->offsetDidChange(); - if (verticalScrollbar->isOverlayScrollbar() && !hasLayerForVerticalScrollbar()) - setScrollbarNeedsPaintInvalidation(VerticalScrollbar); - } if (scrollPositionDouble() != oldPosition) { // FIXME: Pass in DoubleSize. crbug.com/414283.
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp index 87f1f604..d599b4d 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp
@@ -16,6 +16,7 @@ namespace { +using testing::_; using testing::Return; class MockScrollableArea : public NoBaseWillBeGarbageCollectedFinalized<MockScrollableArea>, public ScrollableArea { @@ -30,12 +31,15 @@ MOCK_CONST_METHOD1(scrollSize, int(ScrollbarOrientation)); MOCK_CONST_METHOD0(isScrollCornerVisible, bool()); MOCK_CONST_METHOD0(scrollCornerRect, IntRect()); + MOCK_CONST_METHOD0(horizontalScrollbar, Scrollbar*()); + MOCK_CONST_METHOD0(verticalScrollbar, Scrollbar*()); MOCK_METHOD0(scrollControlWasSetNeedsPaintInvalidation, void()); MOCK_CONST_METHOD0(enclosingScrollableArea, ScrollableArea*()); MOCK_CONST_METHOD1(visibleContentRect, IntRect(IncludeScrollbarsInRect)); MOCK_CONST_METHOD0(contentsSize, IntSize()); MOCK_CONST_METHOD0(scrollableAreaBoundingBox, IntRect()); MOCK_CONST_METHOD0(layerForHorizontalScrollbar, GraphicsLayer*()); + MOCK_CONST_METHOD0(layerForVerticalScrollbar, GraphicsLayer*()); bool userInputScrollable(ScrollbarOrientation) const override { return true; } bool scrollbarsCanBeActive () const override { return true; } @@ -49,6 +53,10 @@ bool scrollAnimatorEnabled() const override { return false; } int pageStep(ScrollbarOrientation) const override { return 0; } + using ScrollableArea::horizontalScrollbarNeedsPaintInvalidation; + using ScrollableArea::verticalScrollbarNeedsPaintInvalidation; + using ScrollableArea::clearNeedsPaintInvalidationForScrollControls; + DEFINE_INLINE_VIRTUAL_TRACE() { ScrollableArea::trace(visitor); @@ -100,6 +108,7 @@ class ScrollbarThemeWithMockInvalidation : public ScrollbarThemeMock { public: MOCK_CONST_METHOD0(shouldRepaintAllPartsOnInvalidation, bool()); + MOCK_CONST_METHOD3(invalidateOnThumbPositionChange, ScrollbarPart(const ScrollbarThemeClient&, float, float)); }; } // namespace @@ -121,18 +130,20 @@ scrollbar->clearThumbNeedsRepaint(); EXPECT_FALSE(scrollbar->trackNeedsRepaint()); EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); - scrollbar->setNeedsPaintInvalidation(NoPart); + scrollbar->setNeedsPaintInvalidation(ThumbPart); EXPECT_TRUE(scrollbar->trackNeedsRepaint()); EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); + // When not all parts are repainted on invalidation, + // setNeedsPaintInvalidation sets repaint bits only on the requested parts. EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(false)); scrollbar->clearTrackNeedsRepaint(); scrollbar->clearThumbNeedsRepaint(); EXPECT_FALSE(scrollbar->trackNeedsRepaint()); EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); - scrollbar->setNeedsPaintInvalidation(NoPart); + scrollbar->setNeedsPaintInvalidation(ThumbPart); EXPECT_FALSE(scrollbar->trackNeedsRepaint()); - EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); + EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); // Forced GC in order to finalize objects depending on the mock object. Heap::collectAllGarbage(); @@ -168,4 +179,102 @@ EXPECT_TRUE(graphicsLayer.hasTrackedPaintInvalidations()); } +TEST_F(ScrollableAreaTest, InvalidatesNonCompositedScrollbarsWhenThumbMoves) +{ + ScrollbarThemeWithMockInvalidation theme; + OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(IntPoint(100, 100)); + RefPtrWillBeRawPtr<Scrollbar> horizontalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), HorizontalScrollbar, RegularScrollbar, &theme); + RefPtrWillBeRawPtr<Scrollbar> verticalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), VerticalScrollbar, RegularScrollbar, &theme); + EXPECT_CALL(*scrollableArea, horizontalScrollbar()).WillRepeatedly(Return(horizontalScrollbar.get())); + EXPECT_CALL(*scrollableArea, verticalScrollbar()).WillRepeatedly(Return(verticalScrollbar.get())); + + // Regardless of whether the theme invalidates any parts, non-composited + // scrollbars have to be repainted if the thumb moves. + EXPECT_CALL(*scrollableArea, layerForHorizontalScrollbar()).WillRepeatedly(Return(nullptr)); + EXPECT_CALL(*scrollableArea, layerForVerticalScrollbar()).WillRepeatedly(Return(nullptr)); + ASSERT_FALSE(scrollableArea->hasLayerForVerticalScrollbar()); + ASSERT_FALSE(scrollableArea->hasLayerForHorizontalScrollbar()); + EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(false)); + EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).WillRepeatedly(Return(NoPart)); + + // A scroll in each direction should only invalidate one scrollbar. + scrollableArea->setScrollPosition(DoublePoint(0, 50), ProgrammaticScroll); + EXPECT_FALSE(scrollableArea->horizontalScrollbarNeedsPaintInvalidation()); + EXPECT_TRUE(scrollableArea->verticalScrollbarNeedsPaintInvalidation()); + scrollableArea->clearNeedsPaintInvalidationForScrollControls(); + scrollableArea->setScrollPosition(DoublePoint(50, 50), ProgrammaticScroll); + EXPECT_TRUE(scrollableArea->horizontalScrollbarNeedsPaintInvalidation()); + EXPECT_FALSE(scrollableArea->verticalScrollbarNeedsPaintInvalidation()); + scrollableArea->clearNeedsPaintInvalidationForScrollControls(); + + // Forced GC in order to finalize objects depending on the mock object. + Heap::collectAllGarbage(); +} + +TEST_F(ScrollableAreaTest, InvalidatesCompositedScrollbarsIfPartsNeedRepaint) +{ + ScrollbarThemeWithMockInvalidation theme; + OwnPtrWillBeRawPtr<MockScrollableArea> scrollableArea = MockScrollableArea::create(IntPoint(100, 100)); + RefPtrWillBeRawPtr<Scrollbar> horizontalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), HorizontalScrollbar, RegularScrollbar, &theme); + horizontalScrollbar->clearTrackNeedsRepaint(); + horizontalScrollbar->clearThumbNeedsRepaint(); + RefPtrWillBeRawPtr<Scrollbar> verticalScrollbar = Scrollbar::createForTesting(scrollableArea.get(), VerticalScrollbar, RegularScrollbar, &theme); + verticalScrollbar->clearTrackNeedsRepaint(); + verticalScrollbar->clearThumbNeedsRepaint(); + EXPECT_CALL(*scrollableArea, horizontalScrollbar()).WillRepeatedly(Return(horizontalScrollbar.get())); + EXPECT_CALL(*scrollableArea, verticalScrollbar()).WillRepeatedly(Return(verticalScrollbar.get())); + + // Composited scrollbars only need repainting when parts become invalid + // (e.g. if the track changes appearance when the thumb reaches the end). + MockGraphicsLayerClient graphicsLayerClient; + MockGraphicsLayer layerForHorizontalScrollbar(&graphicsLayerClient); + layerForHorizontalScrollbar.setDrawsContent(true); + layerForHorizontalScrollbar.setSize(FloatSize(10, 10)); + MockGraphicsLayer layerForVerticalScrollbar(&graphicsLayerClient); + layerForVerticalScrollbar.setDrawsContent(true); + layerForVerticalScrollbar.setSize(FloatSize(10, 10)); + EXPECT_CALL(*scrollableArea, layerForHorizontalScrollbar()).WillRepeatedly(Return(&layerForHorizontalScrollbar)); + EXPECT_CALL(*scrollableArea, layerForVerticalScrollbar()).WillRepeatedly(Return(&layerForVerticalScrollbar)); + ASSERT_TRUE(scrollableArea->hasLayerForHorizontalScrollbar()); + ASSERT_TRUE(scrollableArea->hasLayerForVerticalScrollbar()); + EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(false)); + + // First, we'll scroll horizontally, and the theme will require repainting + // the back button (i.e. the track). + EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).WillOnce(Return(BackButtonStartPart)); + scrollableArea->setScrollPosition(DoublePoint(50, 0), ProgrammaticScroll); + EXPECT_TRUE(layerForHorizontalScrollbar.hasTrackedPaintInvalidations()); + EXPECT_FALSE(layerForVerticalScrollbar.hasTrackedPaintInvalidations()); + EXPECT_TRUE(horizontalScrollbar->trackNeedsRepaint()); + EXPECT_FALSE(horizontalScrollbar->thumbNeedsRepaint()); + layerForHorizontalScrollbar.resetTrackedPaintInvalidations(); + horizontalScrollbar->clearTrackNeedsRepaint(); + + // Next, we'll scroll vertically, but invalidate the thumb. + EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).WillOnce(Return(ThumbPart)); + scrollableArea->setScrollPosition(DoublePoint(50, 50), ProgrammaticScroll); + EXPECT_FALSE(layerForHorizontalScrollbar.hasTrackedPaintInvalidations()); + EXPECT_TRUE(layerForVerticalScrollbar.hasTrackedPaintInvalidations()); + EXPECT_FALSE(verticalScrollbar->trackNeedsRepaint()); + EXPECT_TRUE(verticalScrollbar->thumbNeedsRepaint()); + layerForVerticalScrollbar.resetTrackedPaintInvalidations(); + verticalScrollbar->clearThumbNeedsRepaint(); + + // Next we'll scroll in both, but the thumb position moving requires no + // invalidations. Nonetheless the GraphicsLayer should be invalidated, + // because we still need to update the underlying layer (though no + // rasterization will be required). + EXPECT_CALL(theme, invalidateOnThumbPositionChange(_, _, _)).Times(2).WillRepeatedly(Return(NoPart)); + scrollableArea->setScrollPosition(DoublePoint(70, 70), ProgrammaticScroll); + EXPECT_TRUE(layerForHorizontalScrollbar.hasTrackedPaintInvalidations()); + EXPECT_TRUE(layerForVerticalScrollbar.hasTrackedPaintInvalidations()); + EXPECT_FALSE(horizontalScrollbar->trackNeedsRepaint()); + EXPECT_FALSE(horizontalScrollbar->thumbNeedsRepaint()); + EXPECT_FALSE(verticalScrollbar->trackNeedsRepaint()); + EXPECT_FALSE(verticalScrollbar->thumbNeedsRepaint()); + + // Forced GC in order to finalize objects depending on the mock object. + Heap::collectAllGarbage(); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp index dd67570f..f2071b4 100644 --- a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp +++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
@@ -139,12 +139,14 @@ if (position == m_currentPos) return; + float oldPosition = m_currentPos; int oldThumbPosition = theme().thumbPosition(*this); m_currentPos = position; - // TODO(jbroman): The theme should provide the parts to invalidate. - // At the moment, the only theme that doesn't invalidate everything is Mac, - // which invalidates this as needed in ScrollAnimatorMac. - setNeedsPaintInvalidation(NoPart); + + ScrollbarPart invalidParts = theme().invalidateOnThumbPositionChange( + *this, oldPosition, position); + setNeedsPaintInvalidation(invalidParts); + if (m_pressedPart == ThumbPart) setPressedPos(m_pressedPos + theme().thumbPosition(*this) - oldThumbPosition); }
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.h b/third_party/WebKit/Source/platform/scroll/Scrollbar.h index 295a0e8..d5d704d 100644 --- a/third_party/WebKit/Source/platform/scroll/Scrollbar.h +++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
@@ -97,6 +97,7 @@ int scrollbarThickness() const; // Called by the ScrollableArea when the scroll offset changes. + // Will trigger paint invalidation if required. void offsetDidChange(); void disconnectFromScrollableArea();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h index 8103c98..3b4dd48 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollbarTheme.h
@@ -47,10 +47,8 @@ virtual ~ScrollbarTheme() { } // If true, then scrollbars with this theme will be painted every time - // Scrollbar::setNeedsPaintInvalidation is called. If false, then scrollbar - // thumb and track part painting results will be cached and not repainted - // unless requested by Scrollbar::setThumbNeedsRepaint or - // Scrollbar::setTrackNeedsRepaint. + // Scrollbar::setNeedsPaintInvalidation is called. If false, then only parts + // which are explicitly invalidated will be repainted. virtual bool shouldRepaintAllPartsOnInvalidation() const { return true; } virtual void updateEnabledState(const ScrollbarThemeClient&) { } @@ -71,6 +69,14 @@ virtual bool invalidateOnMouseEnterExit() { return false; } virtual bool invalidateOnWindowActiveChange() const { return false; } + // Returns parts of the scrollbar which must be repainted following a change + // in the thumb position, given scroll positions before and after. + virtual ScrollbarPart invalidateOnThumbPositionChange( + const ScrollbarThemeClient&, float oldPosition, float newPosition) const + { + return AllParts; + } + virtual void paintScrollCorner(GraphicsContext&, const DisplayItemClient&, const IntRect& cornerRect); virtual void paintTickmarks(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) { }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp index f434c09..5e238ef 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.cpp
@@ -43,11 +43,89 @@ namespace blink { +namespace { + static bool useMockTheme() { return LayoutTestSupport::isRunningLayoutTest(); } +// Contains a flag indicating whether WebThemeEngine should paint a UI widget +// for a scrollbar part, and if so, what part and state apply. +// +// If the PartPaintingParams are not affected by a change in the scrollbar +// state, then the corresponding scrollbar part does not need to be repainted. +struct PartPaintingParams { + PartPaintingParams() + : shouldPaint(false) + , part(WebThemeEngine::PartScrollbarDownArrow) + , state(WebThemeEngine::StateNormal) {} + PartPaintingParams(WebThemeEngine::Part part, WebThemeEngine::State state) + : shouldPaint(true) + , part(part) + , state(state) {} + + bool shouldPaint; + WebThemeEngine::Part part; + WebThemeEngine::State state; +}; + +bool operator==(const PartPaintingParams& a, const PartPaintingParams& b) +{ + return (!a.shouldPaint && !b.shouldPaint) || std::tie(a.shouldPaint, a.part, a.state) == std::tie(b.shouldPaint, b.part, b.state); +} + +bool operator!=(const PartPaintingParams& a, const PartPaintingParams& b) +{ + return !(a == b); +} + +PartPaintingParams buttonPartPaintingParams(const ScrollbarThemeClient& scrollbar, float position, ScrollbarPart part) +{ + WebThemeEngine::Part paintPart; + WebThemeEngine::State state = WebThemeEngine::StateNormal; + bool checkMin = false; + bool checkMax = false; + + if (scrollbar.orientation() == HorizontalScrollbar) { + if (part == BackButtonStartPart) { + paintPart = WebThemeEngine::PartScrollbarLeftArrow; + checkMin = true; + } else if (useMockTheme() && part != ForwardButtonEndPart) { + return PartPaintingParams(); + } else { + paintPart = WebThemeEngine::PartScrollbarRightArrow; + checkMax = true; + } + } else { + if (part == BackButtonStartPart) { + paintPart = WebThemeEngine::PartScrollbarUpArrow; + checkMin = true; + } else if (useMockTheme() && part != ForwardButtonEndPart) { + return PartPaintingParams(); + } else { + paintPart = WebThemeEngine::PartScrollbarDownArrow; + checkMax = true; + } + } + + if (useMockTheme() && !scrollbar.enabled()) { + state = WebThemeEngine::StateDisabled; + } else if (!useMockTheme() && ((checkMin && (position <= 0)) + || (checkMax && position >= scrollbar.maximum()))) { + state = WebThemeEngine::StateDisabled; + } else { + if (part == scrollbar.pressedPart()) + state = WebThemeEngine::StatePressed; + else if (part == scrollbar.hoveredPart()) + state = WebThemeEngine::StateHover; + } + + return PartPaintingParams(paintPart, state); +} + +} // namespace + ScrollbarTheme& ScrollbarTheme::nativeTheme() { if (RuntimeEnabledFeatures::overlayScrollbarsEnabled()) { @@ -69,6 +147,24 @@ return scrollbarSize.width(); } +bool ScrollbarThemeAura::shouldRepaintAllPartsOnInvalidation() const +{ + // This theme can separately handle thumb invalidation. + return false; +} + +ScrollbarPart ScrollbarThemeAura::invalidateOnThumbPositionChange(const ScrollbarThemeClient& scrollbar, float oldPosition, float newPosition) const +{ + ScrollbarPart invalidParts = NoPart; + ASSERT(buttonsPlacement() == WebScrollbarButtonsPlacementSingle); + static const ScrollbarPart kButtonParts[] = {BackButtonStartPart, ForwardButtonEndPart}; + for (ScrollbarPart part : kButtonParts) { + if (buttonPartPaintingParams(scrollbar, oldPosition, part) != buttonPartPaintingParams(scrollbar, newPosition, part)) + invalidParts = static_cast<ScrollbarPart>(invalidParts | part); + } + return invalidParts; +} + void ScrollbarThemeAura::paintTrackPiece(GraphicsContext& gc, const ScrollbarThemeClient& scrollbar, const IntRect& rect, ScrollbarPart partType) { DisplayItem::Type displayItemType = trackPiecePartToDisplayItemType(partType); @@ -94,51 +190,14 @@ void ScrollbarThemeAura::paintButton(GraphicsContext& gc, const ScrollbarThemeClient& scrollbar, const IntRect& rect, ScrollbarPart part) { - WebThemeEngine::Part paintPart; - WebThemeEngine::State state = WebThemeEngine::StateNormal; - bool checkMin = false; - bool checkMax = false; - - if (scrollbar.orientation() == HorizontalScrollbar) { - if (part == BackButtonStartPart) { - paintPart = WebThemeEngine::PartScrollbarLeftArrow; - checkMin = true; - } else if (useMockTheme() && part != ForwardButtonEndPart) { - return; - } else { - paintPart = WebThemeEngine::PartScrollbarRightArrow; - checkMax = true; - } - } else { - if (part == BackButtonStartPart) { - paintPart = WebThemeEngine::PartScrollbarUpArrow; - checkMin = true; - } else if (useMockTheme() && part != ForwardButtonEndPart) { - return; - } else { - paintPart = WebThemeEngine::PartScrollbarDownArrow; - checkMax = true; - } - } - DisplayItem::Type displayItemType = buttonPartToDisplayItemType(part); if (DrawingRecorder::useCachedDrawingIfPossible(gc, scrollbar, displayItemType)) return; - + PartPaintingParams params = buttonPartPaintingParams(scrollbar, scrollbar.currentPos(), part); + if (!params.shouldPaint) + return; DrawingRecorder recorder(gc, scrollbar, displayItemType, rect); - - if (useMockTheme() && !scrollbar.enabled()) { - state = WebThemeEngine::StateDisabled; - } else if (!useMockTheme() && ((checkMin && (scrollbar.currentPos() <= 0)) - || (checkMax && scrollbar.currentPos() >= scrollbar.maximum()))) { - state = WebThemeEngine::StateDisabled; - } else { - if (part == scrollbar.pressedPart()) - state = WebThemeEngine::StatePressed; - else if (part == scrollbar.hoveredPart()) - state = WebThemeEngine::StateHover; - } - Platform::current()->themeEngine()->paint(gc.canvas(), paintPart, state, WebRect(rect), 0); + Platform::current()->themeEngine()->paint(gc.canvas(), params.part, params.state, WebRect(rect), 0); } void ScrollbarThemeAura::paintThumb(GraphicsContext& gc, const ScrollbarThemeClient& scrollbar, const IntRect& rect)
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h index b5ddd4f..e09ee56 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeAura.h
@@ -40,6 +40,8 @@ int scrollbarThickness(ScrollbarControlSize) override; protected: + bool shouldRepaintAllPartsOnInvalidation() const override; + ScrollbarPart invalidateOnThumbPositionChange(const ScrollbarThemeClient&, float oldPosition, float newPosition) const override; void paintTrackPiece(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) override; void paintButton(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&, ScrollbarPart) override; void paintThumb(GraphicsContext&, const ScrollbarThemeClient&, const IntRect&) override;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h index be28778c..40c45fa 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.h
@@ -40,6 +40,8 @@ class PLATFORM_EXPORT ScrollbarThemeMacOverlayAPI : public ScrollbarThemeMacCommon { public: bool shouldRepaintAllPartsOnInvalidation() const override { return false; } + ScrollbarPart invalidateOnThumbPositionChange( + const ScrollbarThemeClient&, float oldPosition, float newPosition) const override; void updateEnabledState(const ScrollbarThemeClient&) override; int scrollbarThickness(ScrollbarControlSize = RegularScrollbar) override; bool usesOverlayScrollbars() const override;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm index 955bd6b..960d38e 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm +++ b/third_party/WebKit/Source/platform/scroll/ScrollbarThemeMacOverlayAPI.mm
@@ -104,6 +104,13 @@ return globalSupportsExpandedScrollbars; } +ScrollbarPart ScrollbarThemeMacOverlayAPI::invalidateOnThumbPositionChange( + const ScrollbarThemeClient& scrollbar, float oldPosition, float newPosition) const +{ + // ScrollAnimatorMac will invalidate scrollbar parts if necessary. + return NoPart; +} + void ScrollbarThemeMacOverlayAPI::registerScrollbar(ScrollbarThemeClient& scrollbar) { ScrollbarThemeMacCommon::registerScrollbar(scrollbar);
diff --git a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.cpp b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.cpp index 820402d..a97e957e 100644 --- a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.cpp +++ b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.cpp
@@ -108,12 +108,17 @@ OriginAccessEntry::MatchResult OriginAccessEntry::matchesOrigin(const SecurityOrigin& origin) const { - ASSERT(origin.host() == origin.host().lower()); ASSERT(origin.protocol() == origin.protocol().lower()); if (m_protocol != origin.protocol()) return DoesNotMatchOrigin; + return matchesDomain(origin); +} + +OriginAccessEntry::MatchResult OriginAccessEntry::matchesDomain(const SecurityOrigin& origin) const +{ + ASSERT(origin.host() == origin.host().lower()); // Special case: Include subdomains and empty host means "all hosts, including ip addresses". if (m_subdomainSettings != DisallowSubdomains && m_host.isEmpty()) return MatchesOrigin;
diff --git a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h index d364702..1d2846f3 100644 --- a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h +++ b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntry.h
@@ -62,7 +62,11 @@ // If host is empty string and SubdomainSetting is not DisallowSubdomains, the entry will match all domains in the specified protocol. // IPv6 addresses must include brackets (e.g. '[2001:db8:85a3::8a2e:370:7334]', not '2001:db8:85a3::8a2e:370:7334'). OriginAccessEntry(const String& protocol, const String& host, SubdomainSetting); + + // 'matchesOrigin' requires a protocol match (e.g. 'http' != 'https'). 'matchesDomain' + // relaxes this constraint. MatchResult matchesOrigin(const SecurityOrigin&) const; + MatchResult matchesDomain(const SecurityOrigin&) const; const String& protocol() const { return m_protocol; } const String& host() const { return m_host; }
diff --git a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp index 72d97a3..4136c98 100644 --- a/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp +++ b/third_party/WebKit/Source/platform/weborigin/OriginAccessEntryTest.cpp
@@ -91,24 +91,26 @@ const char* protocol; const char* host; const char* origin; - OriginAccessEntry::MatchResult expected; + OriginAccessEntry::MatchResult expectedOrigin; + OriginAccessEntry::MatchResult expectedDomain; } inputs[] = { - { "http", "example.com", "http://example.com/", OriginAccessEntry::MatchesOrigin }, - { "http", "example.com", "http://www.example.com/", OriginAccessEntry::MatchesOrigin }, - { "http", "example.com", "http://www.www.example.com/", OriginAccessEntry::MatchesOrigin }, - { "http", "www.example.com", "http://example.com/", OriginAccessEntry::DoesNotMatchOrigin }, - { "http", "www.example.com", "http://www.example.com/", OriginAccessEntry::MatchesOrigin }, - { "http", "www.example.com", "http://www.www.example.com/", OriginAccessEntry::MatchesOrigin }, - { "http", "com", "http://example.com/", OriginAccessEntry::MatchesOriginButIsPublicSuffix }, - { "http", "com", "http://www.example.com/", OriginAccessEntry::MatchesOriginButIsPublicSuffix }, - { "http", "com", "http://www.www.example.com/", OriginAccessEntry::MatchesOriginButIsPublicSuffix }, - { "https", "example.com", "http://example.com/", OriginAccessEntry::DoesNotMatchOrigin }, - { "https", "example.com", "http://www.example.com/", OriginAccessEntry::DoesNotMatchOrigin }, - { "https", "example.com", "http://www.www.example.com/", OriginAccessEntry::DoesNotMatchOrigin }, - { "http", "example.com", "http://beispiel.de/", OriginAccessEntry::DoesNotMatchOrigin }, - { "http", "", "http://example.com/", OriginAccessEntry::MatchesOrigin }, - { "http", "", "http://beispiel.de/", OriginAccessEntry::MatchesOrigin }, - { "https", "", "http://beispiel.de/", OriginAccessEntry::DoesNotMatchOrigin }, + { "http", "example.com", "http://example.com/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "example.com", "http://www.example.com/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "example.com", "http://www.www.example.com/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "www.example.com", "http://example.com/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::DoesNotMatchOrigin }, + { "http", "www.example.com", "http://www.example.com/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "www.example.com", "http://www.www.example.com/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "com", "http://example.com/", OriginAccessEntry::MatchesOriginButIsPublicSuffix, OriginAccessEntry::MatchesOriginButIsPublicSuffix }, + { "http", "com", "http://www.example.com/", OriginAccessEntry::MatchesOriginButIsPublicSuffix, OriginAccessEntry::MatchesOriginButIsPublicSuffix }, + { "http", "com", "http://www.www.example.com/", OriginAccessEntry::MatchesOriginButIsPublicSuffix, OriginAccessEntry::MatchesOriginButIsPublicSuffix }, + { "https", "example.com", "http://example.com/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::MatchesOrigin }, + { "https", "example.com", "http://www.example.com/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::MatchesOrigin }, + { "https", "example.com", "http://www.www.example.com/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "example.com", "http://beispiel.de/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::DoesNotMatchOrigin }, + { "http", "example.com", "https://beispiel.de/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::DoesNotMatchOrigin }, + { "http", "", "http://example.com/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "http", "", "http://beispiel.de/", OriginAccessEntry::MatchesOrigin, OriginAccessEntry::MatchesOrigin }, + { "https", "", "http://beispiel.de/", OriginAccessEntry::DoesNotMatchOrigin, OriginAccessEntry::MatchesOrigin }, }; OriginAccessEntryTestPlatform platform; @@ -118,7 +120,8 @@ SCOPED_TRACE(testing::Message() << "Host: " << test.host << ", Origin: " << test.origin); RefPtr<SecurityOrigin> originToTest = SecurityOrigin::createFromString(test.origin); OriginAccessEntry entry1(test.protocol, test.host, OriginAccessEntry::AllowSubdomains); - EXPECT_EQ(test.expected, entry1.matchesOrigin(*originToTest)); + EXPECT_EQ(test.expectedOrigin, entry1.matchesOrigin(*originToTest)); + EXPECT_EQ(test.expectedDomain, entry1.matchesDomain(*originToTest)); } }
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/web/PopupMenuImpl.cpp index 3b8f6b6..169f522 100644 --- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp +++ b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
@@ -501,6 +501,12 @@ if (!m_ownerElement) return; m_needsUpdate = false; + + if (!ownerElement().document().frame()->view()->visibleContentRect().contains(ownerElement().pixelSnappedBoundingBox())) { + hide(); + return; + } + RefPtr<SharedBuffer> data = SharedBuffer::create(); PagePopupClient::addString("window.updateData = {\n", data.get()); PagePopupClient::addString("type: \"update\",\n", data.get()); @@ -521,6 +527,8 @@ } context.finishGroupIfNecessary(); PagePopupClient::addString("],\n", data.get()); + IntRect anchorRectInScreen = m_chromeClient->viewportToScreen(m_ownerElement->elementRectRelativeToViewport()); + addProperty("anchorRectInScreen", anchorRectInScreen, data.get()); PagePopupClient::addString("}\n", data.get()); m_popup->postMessage(String::fromUTF8(data->data(), data->size())); }
diff --git a/third_party/WebKit/Source/web/resources/listPicker.js b/third_party/WebKit/Source/web/resources/listPicker.js index 3d86602..0e25f1c 100644 --- a/third_party/WebKit/Source/web/resources/listPicker.js +++ b/third_party/WebKit/Source/web/resources/listPicker.js
@@ -83,6 +83,13 @@ this._config.baseStyle = window.updateData.baseStyle; this._config.children = window.updateData.children; this._update(); + if (this._config.anchorRectInScreen.x !== window.updateData.anchorRectInScreen.x || + this._config.anchorRectInScreen.y !== window.updateData.anchorRectInScreen.y || + this._config.anchorRectInScreen.width !== window.updateData.anchorRectInScreen.width || + this._config.anchorRectInScreen.height !== window.updateData.anchorRectInScreen.height) { + this._config.anchorRectInScreen = window.updateData.anchorRectInScreen; + this._fixWindowSize(); + } } delete window.updateData; };
diff --git a/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp b/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp index 60be6bbd..b5b63ea 100644 --- a/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp +++ b/third_party/WebKit/Source/web/tests/WebDocumentTest.cpp
@@ -139,11 +139,13 @@ const char* baseURLOriginA = "http://example.test:0/"; const char* baseURLOriginSubA = "http://subdomain.example.test:0/"; +const char* baseURLOriginSecureA = "https://example.test:0/"; const char* baseURLOriginB = "http://not-example.test:0/"; const char* emptyFile = "first_party/empty.html"; const char* nestedData = "first_party/nested-data.html"; const char* nestedOriginA = "first_party/nested-originA.html"; const char* nestedOriginSubA = "first_party/nested-originSubA.html"; +const char* nestedOriginSecureA = "first_party/nested-originSecureA.html"; const char* nestedOriginAInOriginA = "first_party/nested-originA-in-originA.html"; const char* nestedOriginAInOriginB = "first_party/nested-originA-in-originB.html"; const char* nestedOriginB = "first_party/nested-originB.html"; @@ -161,6 +163,11 @@ return toKURL(std::string(baseURLOriginSubA) + file); } +KURL toOriginSecureA(const char* file) +{ + return toKURL(std::string(baseURLOriginSecureA) + file); +} + KURL toOriginB(const char* file) { return toKURL(std::string(baseURLOriginB) + file); @@ -184,6 +191,7 @@ URLTestHelpers::registerMockedURLLoad(toOriginA(nestedData), WebString::fromUTF8(nestedData)); URLTestHelpers::registerMockedURLLoad(toOriginA(nestedOriginA), WebString::fromUTF8(nestedOriginA)); URLTestHelpers::registerMockedURLLoad(toOriginA(nestedOriginSubA), WebString::fromUTF8(nestedOriginSubA)); + URLTestHelpers::registerMockedURLLoad(toOriginA(nestedOriginSecureA), WebString::fromUTF8(nestedOriginSecureA)); URLTestHelpers::registerMockedURLLoad(toOriginA(nestedOriginAInOriginA), WebString::fromUTF8(nestedOriginAInOriginA)); URLTestHelpers::registerMockedURLLoad(toOriginA(nestedOriginAInOriginB), WebString::fromUTF8(nestedOriginAInOriginB)); URLTestHelpers::registerMockedURLLoad(toOriginA(nestedOriginB), WebString::fromUTF8(nestedOriginB)); @@ -192,6 +200,7 @@ URLTestHelpers::registerMockedURLLoad(toOriginA(nestedSrcDoc), WebString::fromUTF8(nestedSrcDoc)); URLTestHelpers::registerMockedURLLoad(toOriginSubA(emptyFile), WebString::fromUTF8(emptyFile)); + URLTestHelpers::registerMockedURLLoad(toOriginSecureA(emptyFile), WebString::fromUTF8(emptyFile)); URLTestHelpers::registerMockedURLLoad(toOriginB(emptyFile), WebString::fromUTF8(emptyFile)); URLTestHelpers::registerMockedURLLoad(toOriginB(nestedOriginA), WebString::fromUTF8(nestedOriginA)); @@ -236,6 +245,14 @@ ASSERT_EQ(toOriginA(nestedOriginSubA), nestedDocument()->firstPartyForCookies()); } +TEST_F(WebDocumentFirstPartyTest, NestedOriginSecureA) +{ + load(nestedOriginSecureA); + + ASSERT_EQ(toOriginA(nestedOriginSecureA), topDocument()->firstPartyForCookies()); + ASSERT_EQ(toOriginA(nestedOriginSecureA), nestedDocument()->firstPartyForCookies()); +} + TEST_F(WebDocumentFirstPartyTest, NestedOriginAInOriginA) { load(nestedOriginAInOriginA);
diff --git a/third_party/WebKit/Source/web/tests/data/first_party/nested-originSecureA.html b/third_party/WebKit/Source/web/tests/data/first_party/nested-originSecureA.html new file mode 100644 index 0000000..b3efe96 --- /dev/null +++ b/third_party/WebKit/Source/web/tests/data/first_party/nested-originSecureA.html
@@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> +<head> + <title>Document with a frame from `https://example.test`.</title> +</head> +<body> + <iframe src="https://example.test:0/first_party/empty.html"></iframe> +</body> +</html>
diff --git a/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h b/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h index 38b285a0..c2b25859 100644 --- a/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h +++ b/third_party/WebKit/Source/wtf/ArrayBufferBuilder.h
@@ -31,6 +31,7 @@ #ifndef ArrayBufferBuilder_h #define ArrayBufferBuilder_h +#include "wtf/Allocator.h" #include "wtf/ArrayBuffer.h" #include "wtf/Noncopyable.h" #include "wtf/RefPtr.h" @@ -40,10 +41,11 @@ // A utility class to build an ArrayBuffer instance. Validity must be checked // by isValid() before using an instance. -class WTF_EXPORT ArrayBufferBuilder { +class WTF_EXPORT ArrayBufferBuilder final { // Disallow copying since it's expensive and we don't want code to do it by // accident. WTF_MAKE_NONCOPYABLE(ArrayBufferBuilder); + USING_FAST_MALLOC(ArrayBufferBuilder); public: // Creates an ArrayBufferBuilder using the default capacity.
diff --git a/third_party/WebKit/Source/wtf/ArrayBufferContents.h b/third_party/WebKit/Source/wtf/ArrayBufferContents.h index 32cfbf4..3050379 100644 --- a/third_party/WebKit/Source/wtf/ArrayBufferContents.h +++ b/third_party/WebKit/Source/wtf/ArrayBufferContents.h
@@ -27,6 +27,7 @@ #ifndef ArrayBufferContents_h #define ArrayBufferContents_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/Noncopyable.h" #include "wtf/RefPtr.h" @@ -38,6 +39,7 @@ class WTF_EXPORT ArrayBufferContents { WTF_MAKE_NONCOPYABLE(ArrayBufferContents); + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: enum InitializationPolicy { ZeroInitialize,
diff --git a/third_party/WebKit/Source/wtf/ArrayPiece.h b/third_party/WebKit/Source/wtf/ArrayPiece.h index 7c7c7f1..fcad5d2 100644 --- a/third_party/WebKit/Source/wtf/ArrayPiece.h +++ b/third_party/WebKit/Source/wtf/ArrayPiece.h
@@ -5,6 +5,7 @@ #ifndef ArrayPiece_h #define ArrayPiece_h +#include "wtf/Allocator.h" #include "wtf/Forward.h" #include "wtf/WTFExport.h" @@ -20,6 +21,7 @@ // IMPORTANT: The data contained by ArrayPiece is NOT OWNED, so caution must be // taken to ensure it is kept alive. class WTF_EXPORT ArrayPiece { + DISALLOW_NEW(); public: // Constructs a "null" ArrayPiece object. ArrayPiece();
diff --git a/third_party/WebKit/Source/wtf/BitArray.h b/third_party/WebKit/Source/wtf/BitArray.h index 2a39c71f..76258b33 100644 --- a/third_party/WebKit/Source/wtf/BitArray.h +++ b/third_party/WebKit/Source/wtf/BitArray.h
@@ -26,6 +26,7 @@ #ifndef BitArray_h #define BitArray_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include <string.h> @@ -33,6 +34,7 @@ template<unsigned arraySize> class BitArray { + USING_FAST_MALLOC(BitArray); public: BitArray(bool value = false) {
diff --git a/third_party/WebKit/Source/wtf/BitVector.h b/third_party/WebKit/Source/wtf/BitVector.h index e540725c..b4d8dea 100644 --- a/third_party/WebKit/Source/wtf/BitVector.h +++ b/third_party/WebKit/Source/wtf/BitVector.h
@@ -26,6 +26,7 @@ #ifndef BitVector_h #define BitVector_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/StdLibExtras.h" #include "wtf/WTFExport.h" @@ -56,6 +57,7 @@ // space. class WTF_EXPORT BitVector { + DISALLOW_NEW(); public: BitVector() : m_bitsOrPointer(makeInlineBits(0)) @@ -195,6 +197,7 @@ } class WTF_EXPORT OutOfLineBits { + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: size_t numBits() const { return m_numBits; } size_t numWords() const { return (m_numBits + bitsInPointer() - 1) / bitsInPointer(); }
diff --git a/third_party/WebKit/Source/wtf/BloomFilter.h b/third_party/WebKit/Source/wtf/BloomFilter.h index a3a36521..1704a827 100644 --- a/third_party/WebKit/Source/wtf/BloomFilter.h +++ b/third_party/WebKit/Source/wtf/BloomFilter.h
@@ -26,6 +26,7 @@ #ifndef BloomFilter_h #define BloomFilter_h +#include "wtf/Allocator.h" #include "wtf/Compiler.h" #include "wtf/text/AtomicString.h" @@ -36,6 +37,7 @@ // keys and m is the table size (==2^keyBits). template <unsigned keyBits> class BloomFilter { + USING_FAST_MALLOC(BloomFilter); public: static_assert(keyBits <= 16, "bloom filter key size check");
diff --git a/third_party/WebKit/Source/wtf/Deque.h b/third_party/WebKit/Source/wtf/Deque.h index 23323c0..cd7bc0c8 100644 --- a/third_party/WebKit/Source/wtf/Deque.h +++ b/third_party/WebKit/Source/wtf/Deque.h
@@ -131,6 +131,7 @@ template <typename T, size_t inlineCapacity, typename Allocator> class DequeIteratorBase { + DISALLOW_NEW(); protected: DequeIteratorBase(); DequeIteratorBase(const Deque<T, inlineCapacity, Allocator>*, size_t);
diff --git a/third_party/WebKit/Source/wtf/DoublyLinkedList.h b/third_party/WebKit/Source/wtf/DoublyLinkedList.h index 1c82226..4440234 100644 --- a/third_party/WebKit/Source/wtf/DoublyLinkedList.h +++ b/third_party/WebKit/Source/wtf/DoublyLinkedList.h
@@ -26,6 +26,8 @@ #ifndef DoublyLinkedList_h #define DoublyLinkedList_h +#include "wtf/Allocator.h" + namespace WTF { // This class allows nodes to share code without dictating data member layout. @@ -67,6 +69,7 @@ } template<typename T> class DoublyLinkedList { + USING_FAST_MALLOC(DoublyLinkedList); public: DoublyLinkedList();
diff --git a/third_party/WebKit/Source/wtf/Functional.h b/third_party/WebKit/Source/wtf/Functional.h index 6035e827..16644a1 100644 --- a/third_party/WebKit/Source/wtf/Functional.h +++ b/third_party/WebKit/Source/wtf/Functional.h
@@ -26,6 +26,7 @@ #ifndef WTF_Functional_h #define WTF_Functional_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/PassOwnPtr.h" #include "wtf/PassRefPtr.h" @@ -49,6 +50,7 @@ // Bound static functions: template<typename R, typename... Params> class FunctionWrapper<R(*)(Params...)> { + DISALLOW_NEW(); public: typedef R ResultType; @@ -70,6 +72,7 @@ template<typename R, typename C, typename... Params> class FunctionWrapper<R(C::*)(Params...)> { + DISALLOW_NEW(); public: typedef R ResultType; @@ -135,6 +138,7 @@ template<typename R, typename... Args> class Function<R(Args...)> { + USING_FAST_MALLOC(Function); WTF_MAKE_NONCOPYABLE(Function); public: virtual ~Function() { }
diff --git a/third_party/WebKit/Source/wtf/HashCountedSet.h b/third_party/WebKit/Source/wtf/HashCountedSet.h index 97340589..58b55f0 100644 --- a/third_party/WebKit/Source/wtf/HashCountedSet.h +++ b/third_party/WebKit/Source/wtf/HashCountedSet.h
@@ -37,6 +37,7 @@ typename Allocator = PartitionAllocator> class HashCountedSet { WTF_USE_ALLOCATOR(HashCountedSet, Allocator); + WTF_MAKE_NONCOPYABLE(HashCountedSet); private: typedef HashMap<Value, unsigned, HashFunctions, Traits, HashTraits<unsigned>, Allocator> ImplType; public:
diff --git a/third_party/WebKit/Source/wtf/HashIterators.h b/third_party/WebKit/Source/wtf/HashIterators.h index e751e9d..2133e84 100644 --- a/third_party/WebKit/Source/wtf/HashIterators.h +++ b/third_party/WebKit/Source/wtf/HashIterators.h
@@ -26,6 +26,8 @@ #ifndef WTF_HashIterators_h #define WTF_HashIterators_h +#include "wtf/Allocator.h" + namespace WTF { template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator; @@ -35,6 +37,7 @@ template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> { + STACK_ALLOCATED(); private: typedef KeyValuePair<KeyType, MappedType> ValueType; public: @@ -59,6 +62,7 @@ template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> { + STACK_ALLOCATED(); private: typedef KeyValuePair<KeyType, MappedType> ValueType; public: @@ -89,6 +93,7 @@ template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator { + STACK_ALLOCATED(); private: typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator; @@ -107,6 +112,7 @@ template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstValuesIterator { + STACK_ALLOCATED(); private: typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator; @@ -125,6 +131,7 @@ template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableKeysIterator { + STACK_ALLOCATED(); private: typedef HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> Iterator; typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator; @@ -150,6 +157,7 @@ template <typename HashTableType, typename KeyType, typename MappedType> struct HashTableValuesIterator { + STACK_ALLOCATED(); private: typedef HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> Iterator; typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
diff --git a/third_party/WebKit/Source/wtf/HashMap.h b/third_party/WebKit/Source/wtf/HashMap.h index 8cb46d4..71c395a 100644 --- a/third_party/WebKit/Source/wtf/HashMap.h +++ b/third_party/WebKit/Source/wtf/HashMap.h
@@ -29,13 +29,16 @@ template <typename KeyTraits, typename MappedTraits> struct HashMapValueTraits; template <typename T> struct ReferenceTypeMaker { + STATIC_ONLY(ReferenceTypeMaker); typedef T& ReferenceType; }; template <typename T> struct ReferenceTypeMaker<T&> { + STATIC_ONLY(ReferenceTypeMaker); typedef T& ReferenceType; }; struct KeyValuePairKeyExtractor { + STATIC_ONLY(KeyValuePairKeyExtractor); template <typename T> static const typename T::KeyType& extract(const T& p) { return p.key; } }; @@ -171,6 +174,7 @@ template <typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg, typename Allocator> class HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator>::HashMapKeysProxy : private HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> { + DISALLOW_NEW(); public: typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> HashMapType; typedef typename HashMapType::iterator::Keys iterator; @@ -209,6 +213,7 @@ template <typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg, typename Allocator> class HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator>::HashMapValuesProxy : private HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> { + DISALLOW_NEW(); public: typedef HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg, Allocator> HashMapType; typedef typename HashMapType::iterator::Values iterator; @@ -246,6 +251,7 @@ template <typename KeyTraits, typename MappedTraits> struct HashMapValueTraits : KeyValuePairHashTraits<KeyTraits, MappedTraits> { + STATIC_ONLY(HashMapValueTraits); static const bool hasIsEmptyValueFunction = true; static bool isEmptyValue(const typename KeyValuePairHashTraits<KeyTraits, MappedTraits>::TraitType& value) { @@ -255,6 +261,7 @@ template <typename ValueTraits, typename HashFunctions> struct HashMapTranslator { + STATIC_ONLY(HashMapTranslator); template <typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); } template <typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); } template <typename T, typename U, typename V> static void translate(T& location, const U& key, const V& mapped) @@ -266,6 +273,7 @@ template <typename ValueTraits, typename Translator> struct HashMapTranslatorAdapter { + STATIC_ONLY(HashMapTranslatorAdapter); template <typename T> static unsigned hash(const T& key) { return Translator::hash(key); } template <typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); } template <typename T, typename U, typename V> static void translate(T& location, const U& key, const V& mapped, unsigned hashCode) @@ -505,6 +513,7 @@ #if !ENABLE(OILPAN) template <typename T, typename U, typename V, typename W, typename X> struct NeedsTracing<HashMap<T, U, V, W, X>> { + STATIC_ONLY(NeedsTracing); static const bool value = false; }; #endif
diff --git a/third_party/WebKit/Source/wtf/HashSet.h b/third_party/WebKit/Source/wtf/HashSet.h index cf37e1ac..08e5902 100644 --- a/third_party/WebKit/Source/wtf/HashSet.h +++ b/third_party/WebKit/Source/wtf/HashSet.h
@@ -124,12 +124,14 @@ }; struct IdentityExtractor { + STATIC_ONLY(IdentityExtractor); template <typename T> static const T& extract(const T& t) { return t; } }; template <typename Translator> struct HashSetTranslatorAdapter { + STATIC_ONLY(HashSetTranslatorAdapter); template <typename T> static unsigned hash(const T& key) { return Translator::hash(key); } template <typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); } template <typename T, typename U> static void translate(T& location, const U& key, const U&, unsigned hashCode)
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h index 960ce296..85b68a72 100644 --- a/third_party/WebKit/Source/wtf/HashTable.h +++ b/third_party/WebKit/Source/wtf/HashTable.h
@@ -21,6 +21,7 @@ #define WTF_HashTable_h #include "wtf/Alignment.h" +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/ConditionalDestructor.h" #include "wtf/HashTraits.h" @@ -72,6 +73,7 @@ #if DUMP_HASHTABLE_STATS struct HashTableStats { + STATIC_ONLY(HashTableStats); // The following variables are all atomically incremented when modified. static int numAccesses; static int numRehashes; @@ -104,7 +106,8 @@ typedef enum { HashItemKnownGood } HashItemKnownGoodTag; template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator> -class HashTableConstIterator { +class HashTableConstIterator final { + DISALLOW_NEW(); private: typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> HashTableType; typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator; @@ -204,7 +207,8 @@ }; template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator> -class HashTableIterator { +class HashTableIterator final { + DISALLOW_NEW(); private: typedef HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> HashTableType; typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator; @@ -260,6 +264,7 @@ template <typename T, typename Allocator, bool useSwap = !IsTriviallyDestructible<T>::value> struct Mover; template <typename T, typename Allocator> struct Mover<T, Allocator, true> { + STATIC_ONLY(Mover); static void move(T& from, T& to) { // The key and value cannot be swapped atomically, and it would be wrong @@ -273,17 +278,20 @@ }; template <typename T, typename Allocator> struct Mover<T, Allocator, false> { + STATIC_ONLY(Mover); static void move(T& from, T& to) { to = from; } }; template <typename HashFunctions> class IdentityHashTranslator { + STATIC_ONLY(IdentityHashTranslator); public: template <typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); } template <typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); } template <typename T, typename U, typename V> static void translate(T& location, const U&, const V& value) { location = value; } }; -template <typename HashTableType, typename ValueType> struct HashTableAddResult { +template <typename HashTableType, typename ValueType> struct HashTableAddResult final { + STACK_ALLOCATED(); HashTableAddResult(const HashTableType* container, ValueType* storedValue, bool isNewEntry) : storedValue(storedValue) , isNewEntry(isNewEntry) @@ -319,6 +327,7 @@ template <typename Value, typename Extractor, typename KeyTraits> struct HashTableHelper { + STATIC_ONLY(HashTableHelper); static bool isEmptyBucket(const Value& value) { return isHashTraitsEmptyValue<KeyTraits>(Extractor::extract(value)); } static bool isDeletedBucket(const Value& value) { return KeyTraits::isDeletedValue(Extractor::extract(value)); } static bool isEmptyOrDeletedBucket(const Value& value) { return isEmptyBucket(value) || isDeletedBucket(value); } @@ -326,6 +335,7 @@ template <typename HashTranslator, typename KeyTraits, bool safeToCompareToEmptyOrDeleted> struct HashTableKeyChecker { + STATIC_ONLY(HashTableKeyChecker); // There's no simple generic way to make this check if // safeToCompareToEmptyOrDeleted is false, so the check always passes. template <typename T> @@ -334,6 +344,7 @@ template <typename HashTranslator, typename KeyTraits> struct HashTableKeyChecker<HashTranslator, KeyTraits, true> { + STATIC_ONLY(HashTableKeyChecker); template <typename T> static bool checkKey(const T& key) { @@ -346,7 +357,8 @@ // undefined behavior. For pointer keys this means that null pointers are not // allowed unless you supply custom key traits. template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator> -class HashTable : public ConditionalDestructor<HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>, Allocator::isGarbageCollected> { +class HashTable final : public ConditionalDestructor<HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator>, Allocator::isGarbageCollected> { + DISALLOW_NEW(); public: typedef HashTableIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> iterator; typedef HashTableConstIterator<Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> const_iterator; @@ -363,6 +375,7 @@ #if DUMP_HASHTABLE_STATS_PER_TABLE struct Stats { + DISALLOW_NEW(Stats); Stats() : numAccesses(0) , numRehashes(0) @@ -768,6 +781,7 @@ template <bool emptyValueIsZero> struct HashTableBucketInitializer; template <> struct HashTableBucketInitializer<false> { + STATIC_ONLY(HashTableBucketInitializer); template <typename Traits, typename Value> static void initialize(Value& bucket) { new (NotNull, &bucket) Value(Traits::emptyValue()); @@ -775,6 +789,7 @@ }; template <> struct HashTableBucketInitializer<true> { + STATIC_ONLY(HashTableBucketInitializer); template <typename Traits, typename Value> static void initialize(Value& bucket) { // This initializes the bucket without copying the empty value. That @@ -1265,6 +1280,7 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator> struct WeakProcessingHashTableHelper<NoWeakHandlingInCollections, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> { + STATIC_ONLY(WeakProcessingHashTableHelper); static void process(typename Allocator::Visitor* visitor, void* closure) {} static void ephemeronIteration(typename Allocator::Visitor* visitor, void* closure) {} static void ephemeronIterationDone(typename Allocator::Visitor* visitor, void* closure) {} @@ -1272,6 +1288,7 @@ template <typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits, typename Allocator> struct WeakProcessingHashTableHelper<WeakHandlingInCollections, Key, Value, Extractor, HashFunctions, Traits, KeyTraits, Allocator> { + STATIC_ONLY(WeakProcessingHashTableHelper); // Used for purely weak and for weak-and-strong tables (ephemerons). static void process(typename Allocator::Visitor* visitor, void* closure) { @@ -1393,6 +1410,7 @@ // iterator adapters template <typename HashTableType, typename Traits> struct HashTableConstIteratorAdapter { + STACK_ALLOCATED(); HashTableConstIteratorAdapter() {} HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {} typedef typename Traits::IteratorConstGetType GetType; @@ -1409,6 +1427,7 @@ }; template <typename HashTableType, typename Traits> struct HashTableIteratorAdapter { + STACK_ALLOCATED(); typedef typename Traits::IteratorGetType GetType; typedef typename HashTableType::ValueTraits::IteratorGetType SourceGetType;
diff --git a/third_party/WebKit/Source/wtf/LinkedHashSet.h b/third_party/WebKit/Source/wtf/LinkedHashSet.h index 58d97fb..9e20239 100644 --- a/third_party/WebKit/Source/wtf/LinkedHashSet.h +++ b/third_party/WebKit/Source/wtf/LinkedHashSet.h
@@ -51,6 +51,7 @@ template<typename Value, typename ValueTraits, typename Allocator> struct LinkedHashSetTraits; class LinkedHashSetNodeBase { + DISALLOW_NEW(); public: LinkedHashSetNodeBase() : m_prev(this), m_next(this) { } @@ -120,6 +121,7 @@ template<typename ValueArg, typename Allocator> class LinkedHashSetNode : public LinkedHashSetNodeBase { + DISALLOW_NEW(); public: LinkedHashSetNode(const ValueArg& value, LinkedHashSetNodeBase* prev, LinkedHashSetNodeBase* next) : LinkedHashSetNodeBase(prev, next) @@ -163,7 +165,8 @@ typedef LinkedHashSetConstReverseIterator<LinkedHashSet> const_reverse_iterator; friend class LinkedHashSetConstReverseIterator<LinkedHashSet>; - struct AddResult { + struct AddResult final { + STACK_ALLOCATED(); AddResult(const typename ImplType::AddResult& hashTableAddResult) : storedValue(&hashTableAddResult.storedValue->m_value) , isNewEntry(hashTableAddResult.isNewEntry) @@ -273,6 +276,7 @@ template<typename Value, typename HashFunctions, typename Allocator> struct LinkedHashSetTranslator { + STATIC_ONLY(LinkedHashSetTranslator); typedef LinkedHashSetNode<Value, Allocator> Node; typedef LinkedHashSetNodeBase NodeBase; typedef typename HashTraits<Value>::PeekInType ValuePeekInType; @@ -295,11 +299,13 @@ template<typename Value, typename Allocator> struct LinkedHashSetExtractor { + STATIC_ONLY(LinkedHashSetExtractor); static const Value& extract(const LinkedHashSetNode<Value, Allocator>& node) { return node.m_value; } }; template<typename Value, typename ValueTraitsArg, typename Allocator> struct LinkedHashSetTraits : public SimpleClassHashTraits<LinkedHashSetNode<Value, Allocator>> { + STATIC_ONLY(LinkedHashSetTraits); typedef LinkedHashSetNode<Value, Allocator> Node; typedef ValueTraitsArg ValueTraits; @@ -319,6 +325,7 @@ // the type inside the node. template<typename U = void> struct NeedsTracingLazily { + STATIC_ONLY(NeedsTracingLazily); static const bool value = ValueTraits::template NeedsTracingLazily<>::value; }; static const WeakHandlingFlag weakHandlingFlag = ValueTraits::weakHandlingFlag; @@ -326,6 +333,7 @@ template<typename LinkedHashSetType> class LinkedHashSetIterator { + DISALLOW_NEW(); private: typedef typename LinkedHashSetType::Node Node; typedef typename LinkedHashSetType::Traits Traits; @@ -368,6 +376,7 @@ template<typename LinkedHashSetType> class LinkedHashSetConstIterator { + DISALLOW_NEW(); private: typedef typename LinkedHashSetType::Node Node; typedef typename LinkedHashSetType::Traits Traits; @@ -571,6 +580,7 @@ template<typename Translator> struct LinkedHashSetTranslatorAdapter { + STATIC_ONLY(LinkedHashSetTranslatorAdapter); template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); } template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a.m_value, b); } }; @@ -723,6 +733,7 @@ #if !ENABLE(OILPAN) template<typename T, typename U, typename V> struct NeedsTracing<LinkedHashSet<T, U, V>> { + STATIC_ONLY(NeedsTracing); static const bool value = false; }; #endif
diff --git a/third_party/WebKit/Source/wtf/LinkedStack.h b/third_party/WebKit/Source/wtf/LinkedStack.h index b63cd06..07ef63c 100644 --- a/third_party/WebKit/Source/wtf/LinkedStack.h +++ b/third_party/WebKit/Source/wtf/LinkedStack.h
@@ -58,9 +58,7 @@ size_t size(); - // This inner class used to be private but is now public on account of a - // possible MSVC bug. It can be made private again if we get rid of - // USING_FAST_MALLOC ever. +private: class Node { USING_FAST_MALLOC(LinkedStack::Node); public: @@ -69,8 +67,10 @@ T m_data; OwnPtr<Node> m_next; }; +#if COMPILER(MSVC) + friend struct ::WTF::OwnedPtrDeleter<Node>; +#endif -private: OwnPtr<Node> m_head; size_t m_size; };
diff --git a/third_party/WebKit/Source/wtf/ListHashSet.h b/third_party/WebKit/Source/wtf/ListHashSet.h index 0c0f26ef..d8710729 100644 --- a/third_party/WebKit/Source/wtf/ListHashSet.h +++ b/third_party/WebKit/Source/wtf/ListHashSet.h
@@ -87,7 +87,8 @@ friend class ListHashSetReverseIterator<ListHashSet>; friend class ListHashSetConstReverseIterator<ListHashSet>; - template <typename ValueType> struct HashTableAddResult { + template <typename ValueType> struct HashTableAddResult final { + STACK_ALLOCATED(); HashTableAddResult(Node* storedValue, bool isNewEntry) : storedValue(storedValue), isNewEntry(isNewEntry) { } Node* storedValue; bool isNewEntry; @@ -193,6 +194,7 @@ // compiler otherwise gets into circular template dependencies when trying to do // sizeof on a node. template <typename ValueArg> class ListHashSetNodeBase { + DISALLOW_NEW(); protected: ListHashSetNodeBase(const ValueArg& value) : m_value(value) @@ -232,6 +234,7 @@ typedef ListHashSetNodeBase<ValueArg> NodeBase; class AllocatorProvider { + DISALLOW_NEW(); public: AllocatorProvider() : m_allocator(nullptr) {} void createAllocatorIfNeeded() @@ -425,12 +428,14 @@ }; template <typename HashArg> struct ListHashSetNodeHashFunctions { + STATIC_ONLY(ListHashSetNodeHashFunctions); template <typename T> static unsigned hash(const T& key) { return HashArg::hash(key->m_value); } template <typename T> static bool equal(const T& a, const T& b) { return HashArg::equal(a->m_value, b->m_value); } static const bool safeToCompareToEmptyOrDeleted = false; }; template <typename Set> class ListHashSetIterator { + DISALLOW_NEW(); private: typedef typename Set::const_iterator const_iterator; typedef typename Set::Node Node; @@ -471,6 +476,7 @@ template <typename Set> class ListHashSetConstIterator { + DISALLOW_NEW(); private: typedef typename Set::const_iterator const_iterator; typedef typename Set::Node Node; @@ -539,6 +545,7 @@ template <typename Set> class ListHashSetReverseIterator { + DISALLOW_NEW(); private: typedef typename Set::const_reverse_iterator const_reverse_iterator; typedef typename Set::Node Node; @@ -578,6 +585,7 @@ }; template <typename Set> class ListHashSetConstReverseIterator { + DISALLOW_NEW(); private: typedef typename Set::reverse_iterator reverse_iterator; typedef typename Set::Node Node; @@ -646,6 +654,7 @@ template <typename HashFunctions> struct ListHashSetTranslator { + STATIC_ONLY(ListHashSetTranslator); template <typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); } template <typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a->m_value, b); } template <typename T, typename U, typename V> static void translate(T*& location, const U& key, const V& allocator) @@ -760,6 +769,7 @@ template <typename Translator> struct ListHashSetTranslatorAdapter { + STATIC_ONLY(ListHashSetTranslatorAdapter); template <typename T> static unsigned hash(const T& key) { return Translator::hash(key); } template <typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); } };
diff --git a/third_party/WebKit/Source/wtf/Locker.h b/third_party/WebKit/Source/wtf/Locker.h index 39b435da..a1f3aba4 100644 --- a/third_party/WebKit/Source/wtf/Locker.h +++ b/third_party/WebKit/Source/wtf/Locker.h
@@ -28,11 +28,13 @@ #ifndef Locker_h #define Locker_h +#include "wtf/Allocator.h" #include "wtf/Noncopyable.h" namespace WTF { -template <typename T> class Locker { +template <typename T> class Locker final { + STACK_ALLOCATED(); WTF_MAKE_NONCOPYABLE(Locker); public: Locker(T& lockable) : m_lockable(lockable) { m_lockable.lock(); }
diff --git a/third_party/WebKit/Source/wtf/MathExtras.h b/third_party/WebKit/Source/wtf/MathExtras.h index 34c2e04..2367947 100644 --- a/third_party/WebKit/Source/wtf/MathExtras.h +++ b/third_party/WebKit/Source/wtf/MathExtras.h
@@ -26,6 +26,7 @@ #ifndef WTF_MathExtras_h #define WTF_MathExtras_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/CPU.h" #include <cmath> @@ -164,6 +165,7 @@ // about unsafe code (even though we wouldn't actually be executing that code). template<bool canUseDirectComparison, typename LimitType, typename ValueType> class ClampToNonLongLongHelper; template<typename LimitType, typename ValueType> class ClampToNonLongLongHelper<true, LimitType, ValueType> { + STATIC_ONLY(ClampToNonLongLongHelper); public: static inline LimitType clampTo(ValueType value, LimitType min, LimitType max) { @@ -172,6 +174,7 @@ }; template<typename LimitType, typename ValueType> class ClampToNonLongLongHelper<false, LimitType, ValueType> { + STATIC_ONLY(ClampToNonLongLongHelper); public: static inline LimitType clampTo(ValueType value, LimitType min, LimitType max) { @@ -217,6 +220,7 @@ // outside the representable range of the limit type, so we also have to check // for that case explicitly. template<typename ValueType> class ClampToHelper<long long int, ValueType> { + STATIC_ONLY(ClampToHelper); public: static inline long long int clampTo(ValueType value, long long int min, long long int max) { @@ -238,6 +242,7 @@ // This specialization handles the case where the above partial specialization // would be potentially incorrect. template<> class ClampToHelper<long long int, unsigned long long int> { + STATIC_ONLY(ClampToHelper); public: static inline long long int clampTo(unsigned long long int value, long long int min, long long int max) { @@ -252,6 +257,7 @@ // but because the lower-bound check is done for integer value types as well, we // don't need a <unsigned long long int, long long int> full specialization. template<typename ValueType> class ClampToHelper<unsigned long long int, ValueType> { + STATIC_ONLY(ClampToHelper); public: static inline unsigned long long int clampTo(ValueType value, unsigned long long int min, unsigned long long int max) {
diff --git a/third_party/WebKit/Source/wtf/Optional.h b/third_party/WebKit/Source/wtf/Optional.h index c4f931e..1c2e422f 100644 --- a/third_party/WebKit/Source/wtf/Optional.h +++ b/third_party/WebKit/Source/wtf/Optional.h
@@ -6,6 +6,7 @@ #define Optional_h #include "wtf/Alignment.h" +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/Noncopyable.h" #include "wtf/StdLibExtras.h" @@ -31,7 +32,8 @@ // optional yields a const reference. template <typename T> -class Optional { +class Optional final { + DISALLOW_NEW(); WTF_MAKE_NONCOPYABLE(Optional); public: Optional() : m_ptr(nullptr) { }
diff --git a/third_party/WebKit/Source/wtf/OwnPtr.h b/third_party/WebKit/Source/wtf/OwnPtr.h index ec09c10e..0b0b58e 100644 --- a/third_party/WebKit/Source/wtf/OwnPtr.h +++ b/third_party/WebKit/Source/wtf/OwnPtr.h
@@ -22,6 +22,7 @@ #ifndef WTF_OwnPtr_h #define WTF_OwnPtr_h +#include "wtf/Allocator.h" #include "wtf/HashTableDeletedValueType.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtrCommon.h" @@ -33,6 +34,7 @@ template <typename T> class PassOwnPtr; template <typename T> class OwnPtr { + USING_FAST_MALLOC(OwnPtr); WTF_MAKE_NONCOPYABLE(OwnPtr); public: typedef typename std::remove_extent<T>::type ValueType;
diff --git a/third_party/WebKit/Source/wtf/OwnPtrCommon.h b/third_party/WebKit/Source/wtf/OwnPtrCommon.h index 301629e..89e24895 100644 --- a/third_party/WebKit/Source/wtf/OwnPtrCommon.h +++ b/third_party/WebKit/Source/wtf/OwnPtrCommon.h
@@ -39,12 +39,14 @@ template<typename T> struct IsRefCounted { + STATIC_ONLY(IsRefCounted); static const bool value = IsSubclass<T, RefCountedBase>::value || IsSubclass<T, ThreadSafeRefCountedBase>::value; }; template <typename T> struct OwnedPtrDeleter { + STATIC_ONLY(OwnedPtrDeleter); static void deletePtr(T* ptr) { static_assert(!IsRefCounted<T>::value, "use RefPtr for RefCounted objects"); @@ -55,6 +57,7 @@ template <typename T> struct OwnedPtrDeleter<T[]> { + STATIC_ONLY(OwnedPtrDeleter); static void deletePtr(T* ptr) { static_assert(!IsRefCounted<T>::value, "use RefPtr for RefCounted objects"); @@ -65,6 +68,7 @@ template <class T, int n> struct OwnedPtrDeleter<T[n]> { + STATIC_ONLY(OwnedPtrDeleter); static_assert(sizeof(T) < 0, "do not use array with size as type"); };
diff --git a/third_party/WebKit/Source/wtf/PartitionAllocator.h b/third_party/WebKit/Source/wtf/PartitionAllocator.h index bf6bcb0..e3b57e5 100644 --- a/third_party/WebKit/Source/wtf/PartitionAllocator.h +++ b/third_party/WebKit/Source/wtf/PartitionAllocator.h
@@ -186,6 +186,7 @@ // The Windows compiler seems to be very eager to instantiate things it won't // need, so unless we have this class we get compile errors. class PartitionAllocatorDummyVisitor { + DISALLOW_NEW(); public: template<typename T> inline bool isHeapObjectAlive(T obj) {
diff --git a/third_party/WebKit/Source/wtf/PassOwnPtr.h b/third_party/WebKit/Source/wtf/PassOwnPtr.h index cde4559..ad3190d 100644 --- a/third_party/WebKit/Source/wtf/PassOwnPtr.h +++ b/third_party/WebKit/Source/wtf/PassOwnPtr.h
@@ -27,6 +27,8 @@ #ifndef WTF_PassOwnPtr_h #define WTF_PassOwnPtr_h +#include "wtf/Allocator.h" +#include "wtf/Noncopyable.h" #include "wtf/OwnPtrCommon.h" namespace WTF { @@ -37,6 +39,7 @@ template <typename T> PassOwnPtr<T[]> adoptArrayPtr(T*); template <typename T> class PassOwnPtr { + DISALLOW_NEW(); public: typedef typename std::remove_extent<T>::type ValueType; typedef ValueType* PtrType; @@ -74,35 +77,15 @@ private: explicit PassOwnPtr(PtrType ptr) : m_ptr(ptr) {} - PassOwnPtr& operator=(const PassOwnPtr&) - { - static_assert(!sizeof(T*), "PassOwnPtr should never be assigned to"); - return *this; - } + PassOwnPtr& operator=(const PassOwnPtr&) = delete; // We should never have two OwnPtrs for the same underlying object // (otherwise we'll get double-destruction), so these equality operators // should never be needed. - template <typename U> bool operator==(const PassOwnPtr<U>&) const - { - static_assert(!sizeof(U*), "OwnPtrs should never be equal"); - return false; - } - template <typename U> bool operator!=(const PassOwnPtr<U>&) const - { - static_assert(!sizeof(U*), "OwnPtrs should never be equal"); - return false; - } - template <typename U> bool operator==(const OwnPtr<U>&) const - { - static_assert(!sizeof(U*), "OwnPtrs should never be equal"); - return false; - } - template <typename U> bool operator!=(const OwnPtr<U>&) const - { - static_assert(!sizeof(U*), "OwnPtrs should never be equal"); - return false; - } + template <typename U> bool operator==(const PassOwnPtr<U>&) const = delete; + template <typename U> bool operator!=(const PassOwnPtr<U>&) const = delete; + template <typename U> bool operator==(const OwnPtr<U>&) const = delete; + template <typename U> bool operator!=(const OwnPtr<U>&) const = delete; mutable PtrType m_ptr; };
diff --git a/third_party/WebKit/Source/wtf/PassRefPtr.h b/third_party/WebKit/Source/wtf/PassRefPtr.h index 8fce6bb..60c91e6 100644 --- a/third_party/WebKit/Source/wtf/PassRefPtr.h +++ b/third_party/WebKit/Source/wtf/PassRefPtr.h
@@ -21,6 +21,7 @@ #ifndef WTF_PassRefPtr_h #define WTF_PassRefPtr_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/RawPtr.h" #include "wtf/TypeTraits.h" @@ -56,6 +57,7 @@ } template <typename T> class PassRefPtr { + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); public: PassRefPtr() : m_ptr(nullptr) {} PassRefPtr(std::nullptr_t) : m_ptr(nullptr) {}
diff --git a/third_party/WebKit/Source/wtf/PrintStream.h b/third_party/WebKit/Source/wtf/PrintStream.h index 4d6888b..27bd33e7 100644 --- a/third_party/WebKit/Source/wtf/PrintStream.h +++ b/third_party/WebKit/Source/wtf/PrintStream.h
@@ -87,7 +87,8 @@ } #define MAKE_PRINT_ADAPTOR(Name, Type, function) \ - class Name { \ + class Name final { \ + STACK_ALLOCATED(); \ public: \ Name(const Type& value) \ : m_value(value) \ @@ -102,7 +103,8 @@ } #define MAKE_PRINT_METHOD_ADAPTOR(Name, Type, method) \ - class Name { \ + class Name final { \ + STACK_ALLOCATED(); \ public: \ Name(const Type& value) \ : m_value(value) \ @@ -127,7 +129,8 @@ MAKE_PRINT_ADAPTOR(CharacterDump, char, dumpCharacter); template <typename T> -class PointerDump { +class PointerDump final { + STACK_ALLOCATED(); public: PointerDump(const T* ptr) : m_ptr(ptr)
diff --git a/third_party/WebKit/Source/wtf/RawPtr.h b/third_party/WebKit/Source/wtf/RawPtr.h index c3a82ec4..a666873 100644 --- a/third_party/WebKit/Source/wtf/RawPtr.h +++ b/third_party/WebKit/Source/wtf/RawPtr.h
@@ -31,6 +31,7 @@ #ifndef WTF_RawPtr_h #define WTF_RawPtr_h +#include "wtf/Allocator.h" #include "wtf/HashTableDeletedValueType.h" #include "wtf/TypeTraits.h" #include <algorithm> @@ -48,6 +49,7 @@ template<typename T> class RawPtr { + USING_FAST_MALLOC(RawPtr); public: RawPtr() {
diff --git a/third_party/WebKit/Source/wtf/RefPtr.h b/third_party/WebKit/Source/wtf/RefPtr.h index 3ccc3a8f..1737fad 100644 --- a/third_party/WebKit/Source/wtf/RefPtr.h +++ b/third_party/WebKit/Source/wtf/RefPtr.h
@@ -23,6 +23,7 @@ #ifndef WTF_RefPtr_h #define WTF_RefPtr_h +#include "wtf/Allocator.h" #include "wtf/HashTableDeletedValueType.h" #include "wtf/PassRefPtr.h" #include "wtf/RawPtr.h" @@ -35,6 +36,7 @@ template <typename T> class RefPtrValuePeeker; template <typename T> class RefPtr { + USING_FAST_MALLOC(RefPtr); public: ALWAYS_INLINE RefPtr() : m_ptr(nullptr) {} ALWAYS_INLINE RefPtr(std::nullptr_t) : m_ptr(nullptr) {} @@ -161,6 +163,7 @@ } template <typename T> class RefPtrValuePeeker { + DISALLOW_NEW(); public: ALWAYS_INLINE RefPtrValuePeeker(T* p): m_ptr(p) {} ALWAYS_INLINE RefPtrValuePeeker(std::nullptr_t): m_ptr(nullptr) {}
diff --git a/third_party/WebKit/Source/wtf/StringHasher.h b/third_party/WebKit/Source/wtf/StringHasher.h index a43d0a7..c4fed75 100644 --- a/third_party/WebKit/Source/wtf/StringHasher.h +++ b/third_party/WebKit/Source/wtf/StringHasher.h
@@ -22,6 +22,7 @@ #ifndef WTF_StringHasher_h #define WTF_StringHasher_h +#include "wtf/Allocator.h" #include "wtf/text/Unicode.h" namespace WTF { @@ -38,6 +39,7 @@ static const unsigned stringHashingStartValue = 0x9E3779B9U; class StringHasher { + DISALLOW_NEW(); public: static const unsigned flagCount = 8; // Save 8 bits for StringImpl to use as flags.
diff --git a/third_party/WebKit/Source/wtf/TerminatedArray.h b/third_party/WebKit/Source/wtf/TerminatedArray.h index 5b867143..6daba4bd 100644 --- a/third_party/WebKit/Source/wtf/TerminatedArray.h +++ b/third_party/WebKit/Source/wtf/TerminatedArray.h
@@ -16,13 +16,15 @@ // TerminatedArray<T> can only be constructed by TerminatedArrayBuilder<T>. template<typename T> class TerminatedArray { + DISALLOW_NEW(); WTF_MAKE_NONCOPYABLE(TerminatedArray); public: T& at(size_t index) { return reinterpret_cast<T*>(this)[index]; } const T& at(size_t index) const { return reinterpret_cast<const T*>(this)[index]; } template<typename U> - class iterator_base { + class iterator_base final { + STACK_ALLOCATED(); public: iterator_base& operator++() { @@ -71,6 +73,7 @@ // Allocator describes how TerminatedArrayBuilder should create new instances // of TerminateArray and manage their lifetimes. struct Allocator { + STATIC_ONLY(Allocator); typedef PassOwnPtr<TerminatedArray> PassPtr; typedef OwnPtr<TerminatedArray> Ptr;
diff --git a/third_party/WebKit/Source/wtf/ThreadSpecific.h b/third_party/WebKit/Source/wtf/ThreadSpecific.h index cbc6b22c..2e82293b 100644 --- a/third_party/WebKit/Source/wtf/ThreadSpecific.h +++ b/third_party/WebKit/Source/wtf/ThreadSpecific.h
@@ -42,6 +42,7 @@ #ifndef WTF_ThreadSpecific_h #define WTF_ThreadSpecific_h +#include "wtf/Allocator.h" #include "wtf/Noncopyable.h" #include "wtf/Partitions.h" #include "wtf/StdLibExtras.h" @@ -63,6 +64,7 @@ #endif template<typename T> class ThreadSpecific { + USING_FAST_MALLOC(ThreadSpecific); WTF_MAKE_NONCOPYABLE(ThreadSpecific); public: ThreadSpecific();
diff --git a/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp b/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp index 6ed83652..da2e0d4a 100644 --- a/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp +++ b/third_party/WebKit/Source/wtf/ThreadSpecificWin.cpp
@@ -25,6 +25,7 @@ #include "StdLibExtras.h" #include "ThreadingPrimitives.h" +#include "wtf/Allocator.h" #include "wtf/DoublyLinkedList.h" namespace WTF { @@ -42,6 +43,8 @@ } class PlatformThreadSpecificKey : public DoublyLinkedListNode<PlatformThreadSpecificKey> { + USING_FAST_MALLOC(PlatformThreadSpecificKey); + WTF_MAKE_NONCOPYABLE(PlatformThreadSpecificKey); public: friend class DoublyLinkedListNode<PlatformThreadSpecificKey>;
diff --git a/third_party/WebKit/Source/wtf/ThreadingPrimitives.h b/third_party/WebKit/Source/wtf/ThreadingPrimitives.h index 0229d35..f5b8d75 100644 --- a/third_party/WebKit/Source/wtf/ThreadingPrimitives.h +++ b/third_party/WebKit/Source/wtf/ThreadingPrimitives.h
@@ -110,7 +110,8 @@ typedef Locker<MutexBase> MutexLocker; -class MutexTryLocker { +class MutexTryLocker final { + STACK_ALLOCATED(); WTF_MAKE_NONCOPYABLE(MutexTryLocker); public: MutexTryLocker(Mutex& mutex) : m_mutex(mutex), m_locked(mutex.tryLock()) { } @@ -127,7 +128,8 @@ bool m_locked; }; -class WTF_EXPORT ThreadCondition { +class WTF_EXPORT ThreadCondition final { + USING_FAST_MALLOC(ThreadCondition); // Only HeapTest.cpp requires. WTF_MAKE_NONCOPYABLE(ThreadCondition); public: ThreadCondition();
diff --git a/third_party/WebKit/Source/wtf/Vector.h b/third_party/WebKit/Source/wtf/Vector.h index c9a2e659..73301493 100644 --- a/third_party/WebKit/Source/wtf/Vector.h +++ b/third_party/WebKit/Source/wtf/Vector.h
@@ -60,11 +60,13 @@ template <typename T> struct VectorDestructor<false, T> { + STATIC_ONLY(VectorDestructor); static void destruct(T*, T*) {} }; template <typename T> struct VectorDestructor<true, T> { + STATIC_ONLY(VectorDestructor); static void destruct(T* begin, T* end) { for (T* cur = begin; cur != end; ++cur) @@ -77,6 +79,7 @@ template <typename T> struct VectorUnusedSlotClearer<false, T> { + STATIC_ONLY(VectorUnusedSlotClearer); static void clear(T*, T*) {} #if ENABLE(ASSERT) static void checkCleared(const T*, const T*) {} @@ -85,6 +88,7 @@ template <typename T> struct VectorUnusedSlotClearer<true, T> { + STATIC_ONLY(VectorUnusedSlotClearer); static void clear(T* begin, T* end) { memset(reinterpret_cast<void*>(begin), 0, sizeof(T) * (end - begin)); @@ -107,6 +111,7 @@ template <typename T> struct VectorInitializer<false, T> { + STATIC_ONLY(VectorInitializer); static void initialize(T* begin, T* end) { for (T* cur = begin; cur != end; ++cur) @@ -116,6 +121,7 @@ template <typename T> struct VectorInitializer<true, T> { + STATIC_ONLY(VectorInitializer); static void initialize(T* begin, T* end) { memset(begin, 0, reinterpret_cast<char*>(end) - reinterpret_cast<char*>(begin)); @@ -127,6 +133,7 @@ template <typename T> struct VectorMover<false, T> { + STATIC_ONLY(VectorMover); static void move(T* src, T* srcEnd, T* dst) { while (src != srcEnd) { @@ -158,6 +165,7 @@ template <typename T> struct VectorMover<true, T> { + STATIC_ONLY(VectorMover); static void move(const T* src, const T* srcEnd, T* dst) { if (LIKELY(dst && src)) @@ -179,6 +187,7 @@ template <typename T> struct VectorCopier<false, T> { + STATIC_ONLY(VectorCopier); template <typename U> static void uninitializedCopy(const U* src, const U* srcEnd, T* dst) { @@ -192,6 +201,7 @@ template <typename T> struct VectorCopier<true, T> { + STATIC_ONLY(VectorCopier); static void uninitializedCopy(const T* src, const T* srcEnd, T* dst) { if (LIKELY(dst && src)) @@ -209,6 +219,7 @@ template <typename T> struct VectorFiller<false, T> { + STATIC_ONLY(VectorFiller); static void uninitializedFill(T* dst, T* dstEnd, const T& val) { while (dst != dstEnd) { @@ -220,6 +231,7 @@ template <typename T> struct VectorFiller<true, T> { + STATIC_ONLY(VectorFiller); static void uninitializedFill(T* dst, T* dstEnd, const T& val) { static_assert(sizeof(T) == sizeof(char), "size of type should be one"); @@ -237,6 +249,7 @@ template <typename T> struct VectorComparer<false, T> { + STATIC_ONLY(VectorComparer); static bool compare(const T* a, const T* b, size_t size) { ASSERT(a); @@ -247,6 +260,7 @@ template <typename T> struct VectorComparer<true, T> { + STATIC_ONLY(VectorComparer); static bool compare(const T* a, const T* b, size_t size) { ASSERT(a); @@ -257,6 +271,7 @@ template <typename T> struct VectorTypeOperations { + STATIC_ONLY(VectorTypeOperations); static void destruct(T* begin, T* end) { VectorDestructor<VectorTraits<T>::needsDestruction, T>::destruct(begin, end); @@ -301,6 +316,7 @@ template <typename T, bool hasInlineCapacity, typename Allocator> class VectorBufferBase { WTF_MAKE_NONCOPYABLE(VectorBufferBase); + DISALLOW_NEW(); public: void allocateBuffer(size_t newCapacity) { @@ -1349,6 +1365,7 @@ #if !ENABLE(OILPAN) template <typename T, size_t N> struct NeedsTracing<Vector<T, N>> { + STATIC_ONLY(NeedsTracing); static const bool value = false; }; #endif
diff --git a/third_party/WebKit/Source/wtf/WTFThreadData.h b/third_party/WebKit/Source/wtf/WTFThreadData.h index 0dbd7e7..41526e2c 100644 --- a/third_party/WebKit/Source/wtf/WTFThreadData.h +++ b/third_party/WebKit/Source/wtf/WTFThreadData.h
@@ -43,6 +43,7 @@ typedef void (*AtomicStringTableDestructor)(AtomicStringTable*); class WTF_EXPORT WTFThreadData { + DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); WTF_MAKE_NONCOPYABLE(WTFThreadData); public: WTFThreadData();
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.cpp b/third_party/WebKit/Source/wtf/text/AtomicString.cpp index 88a80d6..723d8bd69 100644 --- a/third_party/WebKit/Source/wtf/text/AtomicString.cpp +++ b/third_party/WebKit/Source/wtf/text/AtomicString.cpp
@@ -36,6 +36,7 @@ static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must be same size"); class AtomicStringTable { + USING_FAST_MALLOC(AtomicStringTable); WTF_MAKE_NONCOPYABLE(AtomicStringTable); public: static AtomicStringTable* create(WTFThreadData& data)
diff --git a/third_party/WebKit/Source/wtf/text/StringBuffer.h b/third_party/WebKit/Source/wtf/text/StringBuffer.h index f38e0cf..bca6c47 100644 --- a/third_party/WebKit/Source/wtf/text/StringBuffer.h +++ b/third_party/WebKit/Source/wtf/text/StringBuffer.h
@@ -29,6 +29,7 @@ #ifndef StringBuffer_h #define StringBuffer_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/text/StringImpl.h" #include "wtf/text/Unicode.h" @@ -37,6 +38,7 @@ template <typename CharType> class StringBuffer { + DISALLOW_NEW(); WTF_MAKE_NONCOPYABLE(StringBuffer); public: StringBuffer() { }
diff --git a/third_party/WebKit/Source/wtf/text/StringConcatenate.h b/third_party/WebKit/Source/wtf/text/StringConcatenate.h index 01e1463..70bb0bd 100644 --- a/third_party/WebKit/Source/wtf/text/StringConcatenate.h +++ b/third_party/WebKit/Source/wtf/text/StringConcatenate.h
@@ -26,6 +26,7 @@ #ifndef StringConcatenate_h #define StringConcatenate_h +#include "wtf/Allocator.h" #include <string.h> #ifndef WTFString_h @@ -42,10 +43,12 @@ template<typename StringType> class StringTypeAdapter { + DISALLOW_NEW(); }; template<> class StringTypeAdapter<char> { + DISALLOW_NEW(); public: StringTypeAdapter<char>(char buffer) : m_buffer(buffer) @@ -69,6 +72,7 @@ template<> class StringTypeAdapter<LChar> { + DISALLOW_NEW(); public: StringTypeAdapter<LChar>(LChar buffer) : m_buffer(buffer) @@ -92,6 +96,7 @@ template<> class StringTypeAdapter<UChar> { + DISALLOW_NEW(); public: StringTypeAdapter<UChar>(UChar buffer) : m_buffer(buffer) @@ -116,6 +121,7 @@ template<> class WTF_EXPORT StringTypeAdapter<char*> { + DISALLOW_NEW(); public: StringTypeAdapter<char*>(char* buffer) : m_buffer(buffer) @@ -138,6 +144,7 @@ template<> class WTF_EXPORT StringTypeAdapter<LChar*> { + DISALLOW_NEW(); public: StringTypeAdapter<LChar*>(LChar* buffer); @@ -156,6 +163,7 @@ template<> class WTF_EXPORT StringTypeAdapter<const UChar*> { + DISALLOW_NEW(); public: StringTypeAdapter(const UChar* buffer); @@ -177,6 +185,7 @@ template<> class WTF_EXPORT StringTypeAdapter<const char*> { + DISALLOW_NEW(); public: StringTypeAdapter<const char*>(const char* buffer); @@ -195,6 +204,7 @@ template<> class WTF_EXPORT StringTypeAdapter<const LChar*> { + DISALLOW_NEW(); public: StringTypeAdapter<const LChar*>(const LChar* buffer); @@ -213,6 +223,7 @@ template<> class WTF_EXPORT StringTypeAdapter<Vector<char>> { + DISALLOW_NEW(); public: StringTypeAdapter<Vector<char>>(const Vector<char>& buffer) : m_buffer(buffer) @@ -233,6 +244,7 @@ template<> class StringTypeAdapter<Vector<LChar>> { + DISALLOW_NEW(); public: StringTypeAdapter<Vector<LChar>>(const Vector<LChar>& buffer) : m_buffer(buffer) @@ -253,6 +265,7 @@ template<> class WTF_EXPORT StringTypeAdapter<String> { + DISALLOW_NEW(); public: StringTypeAdapter<String>(const String& string) : m_buffer(string) @@ -273,6 +286,7 @@ template<> class StringTypeAdapter<AtomicString> { + DISALLOW_NEW(); public: StringTypeAdapter<AtomicString>(const AtomicString& string) : m_adapter(string.string())
diff --git a/third_party/WebKit/Source/wtf/text/StringHash.h b/third_party/WebKit/Source/wtf/text/StringHash.h index d10554f..7f0fcb2 100644 --- a/third_party/WebKit/Source/wtf/text/StringHash.h +++ b/third_party/WebKit/Source/wtf/text/StringHash.h
@@ -22,6 +22,7 @@ #ifndef StringHash_h #define StringHash_h +#include "wtf/Allocator.h" #include "wtf/HashTraits.h" #include "wtf/StringHasher.h" #include "wtf/text/AtomicString.h" @@ -43,6 +44,7 @@ // place. struct StringHash { + STATIC_ONLY(StringHash); static unsigned hash(StringImpl* key) { return key->hash(); } static inline bool equal(const StringImpl* a, const StringImpl* b) { @@ -65,6 +67,7 @@ }; class CaseFoldingHash { + STATIC_ONLY(CaseFoldingHash); public: static unsigned hash(const UChar* data, unsigned length) { @@ -141,6 +144,7 @@ // don't want to store the string. It's not really specific to string hashing, // but all our current uses of it are for strings. struct AlreadyHashed : IntHash<unsigned> { + STATIC_ONLY(AlreadyHashed); static unsigned hash(unsigned key) { return key; } // To use a hash value as a key for a hash table, we need to eliminate the
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp index a7565fd7..2a46f3bd 100644 --- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp +++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -900,7 +900,8 @@ return create(characters16() + start, end + 1 - start); } -class UCharPredicate { +class UCharPredicate final { + STACK_ALLOCATED(); public: inline UCharPredicate(CharacterMatchFunctionPtr function): m_function(function) { } @@ -913,7 +914,8 @@ const CharacterMatchFunctionPtr m_function; }; -class SpaceOrNewlinePredicate { +class SpaceOrNewlinePredicate final { + STACK_ALLOCATED(); public: inline bool operator()(UChar ch) const {
diff --git a/third_party/WebKit/Source/wtf/text/StringOperators.h b/third_party/WebKit/Source/wtf/text/StringOperators.h index b2e5385f..9100cda 100644 --- a/third_party/WebKit/Source/wtf/text/StringOperators.h +++ b/third_party/WebKit/Source/wtf/text/StringOperators.h
@@ -22,12 +22,14 @@ #ifndef StringOperators_h #define StringOperators_h -#include "StringConcatenate.h" +#include "wtf/Allocator.h" +#include "wtf/text/StringConcatenate.h" namespace WTF { template<typename StringType1, typename StringType2> -class StringAppend { +class StringAppend final { + STACK_ALLOCATED(); public: StringAppend(StringType1 string1, StringType2 string2); @@ -104,6 +106,7 @@ template<typename StringType1, typename StringType2> class StringTypeAdapter<StringAppend<StringType1, StringType2>> { + STACK_ALLOCATED(); public: StringTypeAdapter<StringAppend<StringType1, StringType2>>(StringAppend<StringType1, StringType2>& buffer) : m_buffer(buffer)
diff --git a/third_party/WebKit/Source/wtf/text/StringStatics.h b/third_party/WebKit/Source/wtf/text/StringStatics.h index b241894..e2c34dda 100644 --- a/third_party/WebKit/Source/wtf/text/StringStatics.h +++ b/third_party/WebKit/Source/wtf/text/StringStatics.h
@@ -31,16 +31,15 @@ #ifndef StringStatics_h #define StringStatics_h +#include "wtf/Allocator.h" #include "wtf/WTFExport.h" namespace WTF { class StringStatics { + STATIC_ONLY(StringStatics); public: WTF_EXPORT static void init(); - -private: - StringStatics(); }; }
diff --git a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h index 10928b3..e330c85a 100644 --- a/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h +++ b/third_party/WebKit/Source/wtf/text/StringUTF8Adaptor.h
@@ -32,6 +32,7 @@ #define StringUTF8Adaptor_h #include "base/strings/string_piece.h" +#include "wtf/Allocator.h" #include "wtf/text/CString.h" #include "wtf/text/TextEncoding.h" #include "wtf/text/WTFString.h" @@ -41,7 +42,8 @@ // This class lets you get UTF-8 data out of a String without mallocing a // separate buffer to hold the data if the String happens to be 8 bit and // contain only ASCII characters. -class StringUTF8Adaptor { +class StringUTF8Adaptor final { + DISALLOW_NEW(); public: explicit StringUTF8Adaptor(const String& string) : m_data(0)
diff --git a/third_party/WebKit/Source/wtf/text/StringView.h b/third_party/WebKit/Source/wtf/text/StringView.h index dc92fa3..40b0b94 100644 --- a/third_party/WebKit/Source/wtf/text/StringView.h +++ b/third_party/WebKit/Source/wtf/text/StringView.h
@@ -31,11 +31,13 @@ #ifndef WTF_StringView_h #define WTF_StringView_h +#include "wtf/Allocator.h" #include "wtf/text/StringImpl.h" namespace WTF { class WTF_EXPORT StringView { + DISALLOW_NEW(); public: StringView() : m_offset(0)
diff --git a/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp b/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp index c63669e1..f90d447c 100644 --- a/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp +++ b/third_party/WebKit/Source/wtf/text/TextCodecICU.cpp
@@ -305,7 +305,8 @@ return target - targetStart; } -class ErrorCallbackSetter { +class ErrorCallbackSetter final { + STACK_ALLOCATED(); public: ErrorCallbackSetter(UConverter* converter, bool stopOnError) : m_converter(converter) @@ -473,7 +474,8 @@ } #endif // USING_SYSTEM_ICU -class TextCodecInput { +class TextCodecInput final { + STACK_ALLOCATED(); public: TextCodecInput(const TextEncoding& encoding, const UChar* characters, size_t length) : m_begin(characters)
diff --git a/third_party/WebKit/Source/wtf/text/TextEncoding.h b/third_party/WebKit/Source/wtf/text/TextEncoding.h index bb40b961..1b97e13 100644 --- a/third_party/WebKit/Source/wtf/text/TextEncoding.h +++ b/third_party/WebKit/Source/wtf/text/TextEncoding.h
@@ -26,6 +26,7 @@ #ifndef TextEncoding_h #define TextEncoding_h +#include "wtf/Allocator.h" #include "wtf/Forward.h" #include "wtf/WTFExport.h" #include "wtf/text/TextCodec.h" @@ -33,7 +34,8 @@ namespace WTF { -class WTF_EXPORT TextEncoding { +class WTF_EXPORT TextEncoding final { + USING_FAST_MALLOC(TextEncoding); public: TextEncoding() : m_name(0) { } TextEncoding(const char* name);
diff --git a/third_party/WebKit/Source/wtf/text/TextPosition.h b/third_party/WebKit/Source/wtf/text/TextPosition.h index 8626054b..17140c3 100644 --- a/third_party/WebKit/Source/wtf/text/TextPosition.h +++ b/third_party/WebKit/Source/wtf/text/TextPosition.h
@@ -25,6 +25,7 @@ #ifndef TextPosition_h #define TextPosition_h +#include "wtf/Allocator.h" #include "wtf/Assertions.h" #include "wtf/Vector.h" #include "wtf/WTFExport.h" @@ -35,7 +36,8 @@ // An abstract number of element in a sequence. The sequence has a first element. // This type should be used instead of integer because 2 contradicting traditions can // call a first element '0' or '1' which makes integer type ambiguous. -class OrdinalNumber { +class OrdinalNumber final { + DISALLOW_NEW(); public: static OrdinalNumber fromZeroBasedInt(int zeroBasedInt) { return OrdinalNumber(zeroBasedInt); } static OrdinalNumber fromOneBasedInt(int oneBasedInt) { return OrdinalNumber(oneBasedInt - 1); } @@ -58,7 +60,8 @@ // TextPosition structure specifies coordinates within an text resource. It is used mostly // for saving script source position. -class TextPosition { +class TextPosition final { + DISALLOW_NEW(); public: TextPosition(OrdinalNumber line, OrdinalNumber column) : m_line(line)
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium index 34a565f..a003a76 100644 --- a/third_party/libjingle/README.chromium +++ b/third_party/libjingle/README.chromium
@@ -1,7 +1,7 @@ Name: libjingle URL: http://www.webrtc.org Version: unknown -Revision: 11290 +Revision: 11304 License: BSD License File: source/talk/COPYING Security Critical: yes
diff --git a/third_party/openh264/openh264.gyp b/third_party/openh264/openh264.gyp index 4d46bfc..388e655 100644 --- a/third_party/openh264/openh264.gyp +++ b/third_party/openh264/openh264.gyp
@@ -44,12 +44,13 @@ # resort to using |AdditionalOptions| instead. 'msvs_settings': { 'VCCLCompilerTool': { + 'AdditionalOptions': [ + '-Wno-unused-function', + '-Wno-unused-value', + ], 'AdditionalOptions!': [ '-Wheader-hygiene', ], - 'AdditionalOptions': [ - '-Wno-unused-value', - ], }, }, }],
diff --git a/tools/android/loading/loading_trace.py b/tools/android/loading/loading_trace.py new file mode 100644 index 0000000..720fa1d1 --- /dev/null +++ b/tools/android/loading/loading_trace.py
@@ -0,0 +1,55 @@ +# Copyright (c) 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. + +"""Represents the trace of a page load.""" + +import page_track +import request_track +import tracing + +class LoadingTrace(object): + """Represents the trace of a page load.""" + _URL_KEY = 'url' + _METADATA_KEY = 'metadata' + _PAGE_KEY = 'page_track' + _REQUEST_KEY = 'request_track' + _TRACING_KEY = 'tracing_track' + + def __init__(self, url, metadata, page, request, tracing_track): + """Initializes a loading trace instance. + + Args: + url: (str) URL that has been loaded + metadata: (dict) Metadata associated with the load. + page: (PageTrack) instance of PageTrack. + request: (RequestTrack) instance of RequestTrack. + tracing_track: (TracingTrack) instance of TracingTrack. + """ + self.url = url + self.metadata = metadata + self.page_track = page + self.request_track = request + self.tracing_track = tracing_track + + def ToJsonDict(self): + """Returns a dictionary representing this instance.""" + result = {self._URL_KEY: self.url, self._METADATA_KEY: self.metadata, + self._PAGE_KEY: self.page_track.ToJsonDict(), + self._REQUEST_KEY: self.request_track.ToJsonDict(), + self._TRACING_KEY: self.tracing_track.ToJsonDict()} + return result + + @classmethod + def FromJsonDict(cls, json_dict): + """Returns an instance from a dictionary returned by ToJsonDict().""" + keys = (cls._URL_KEY, cls._METADATA_KEY, cls._PAGE_KEY, cls._REQUEST_KEY, + cls._TRACING_KEY) + assert all(key in json_dict for key in keys) + page = page_track.PageTrack.FromJsonDict(json_dict[cls._PAGE_KEY]) + request = request_track.RequestTrack.FromJsonDict( + json_dict[cls._REQUEST_KEY]) + tracing_track = tracing.TracingTrack.FromJsonDict( + json_dict[cls._TRACING_KEY]) + return LoadingTrace(json_dict[cls._URL_KEY], json_dict[cls._METADATA_KEY], + page, request, tracing_track)
diff --git a/tools/android/loading/request_track.py b/tools/android/loading/request_track.py index 08e15880..7130965 100644 --- a/tools/android/loading/request_track.py +++ b/tools/android/loading/request_track.py
@@ -230,7 +230,12 @@ # network stack. ('requestHeaders', 'request_headers'), ('headers', 'response_headers'))) - timing_dict = response['timing'] if r.protocol != 'data' else {} + # data URLs don't have a timing dict. + timing_dict = {} + if r.protocol != 'data': + timing_dict = response['timing'] + else: + timing_dict = {'requestTime': r.timestamp} r.timing = _TimingFromDict(timing_dict) self._requests_in_flight[request_id] = (r, RequestTrack._STATUS_RESPONSE) @@ -291,7 +296,8 @@ def _CopyFromDictToObject(d, o, key_attrs): for (key, attr) in key_attrs: - setattr(o, attr, d[key]) + if key in d: + setattr(o, attr, d[key]) if __name__ == '__main__':
diff --git a/tools/android/loading/trace_recorder.py b/tools/android/loading/trace_recorder.py index 0b96225..fdf6cc6 100755 --- a/tools/android/loading/trace_recorder.py +++ b/tools/android/loading/trace_recorder.py
@@ -5,8 +5,13 @@ """Loading trace recorder.""" +import argparse +import datetime +import json +import logging import os import sys +import time _SRC_DIR = os.path.abspath(os.path.join( os.path.dirname(__file__), '..', '..', '..')) @@ -19,32 +24,43 @@ import device_setup import devtools_monitor +import loading_trace import page_track - -class AndroidTraceRecorder(object): - """Records a loading trace.""" - def __init__(self, url): - self.url = url - self.devtools_connection = None - self.page_track = None - - def Go(self, connection): - self.devtools_connection = connection - self.page_track = page_track.PageTrack(self.devtools_connection) - self.devtools_connection.SetUpMonitoring() - self.devtools_connection.SendAndIgnoreResponse( - 'Page.navigate', {'url': self.url}) - self.devtools_connection.StartMonitoring() - print self.page_track.GetEvents() +import request_track +import tracing -def DoIt(url): +def RecordAndDumpTrace(device, url, output_filename): + with file(output_filename, 'w') as output,\ + device_setup.DeviceConnection(device) as connection: + page = page_track.PageTrack(connection) + request = request_track.RequestTrack(connection) + tracing_track = tracing.TracingTrack(connection) + connection.SetUpMonitoring() + connection.SendAndIgnoreResponse('Network.clearBrowserCache', {}) + connection.SendAndIgnoreResponse('Page.navigate', {'url': url}) + connection.StartMonitoring() + metadata = {'date': datetime.datetime.utcnow().isoformat(), + 'seconds_since_epoch': time.time()} + trace = loading_trace.LoadingTrace(url, metadata, page, request, + tracing_track) + json.dump(trace.ToJsonDict(), output) + + +def main(): + logging.basicConfig(level=logging.INFO) devil_chromium.Initialize() - devices = device_utils.DeviceUtils.HealthyDevices() - device = devices[0] - trace_recorder = AndroidTraceRecorder(url) - device_setup.SetUpAndExecute(device, 'chrome', trace_recorder.Go) + + parser = argparse.ArgumentParser() + parser.add_argument('--url', required=True) + parser.add_argument('--output', required=True) + args = parser.parse_args() + url = args.url + if not url.startswith('http'): + url = 'http://' + url + device = device_utils.DeviceUtils.HealthyDevices()[0] + RecordAndDumpTrace(device, url, args.output) if __name__ == '__main__': - DoIt(sys.argv[1]) + main()
diff --git a/tools/android/loading/tracing.py b/tools/android/loading/tracing.py index 83ad38c1..47a0ae3b 100644 --- a/tools/android/loading/tracing.py +++ b/tools/android/loading/tracing.py
@@ -4,9 +4,17 @@ """Monitor tracing events on chrome via chrome remote debugging.""" +import bisect +import itertools + import devtools_monitor + class TracingTrack(devtools_monitor.Track): + """Grabs and processes trace event messages. + + See https://goo.gl/Qabkqk for details on the protocol. + """ def __init__(self, connection, categories=None, fetch_stream=False): """Initialize this TracingTrack. @@ -20,7 +28,8 @@ a stream is slower than the default reporting as dataCollected events. """ super(TracingTrack, self).__init__(connection) - connection.RegisterListener('Tracing.dataCollected', self) + if connection: + connection.RegisterListener('Tracing.dataCollected', self) params = {} if categories: params['categories'] = (categories if type(categories) is str @@ -28,11 +37,346 @@ if fetch_stream: params['transferMode'] = 'ReturnAsStream' - connection.SyncRequestNoResponse('Tracing.start', params) + if connection: + connection.SyncRequestNoResponse('Tracing.start', params) self._events = [] + self._event_msec_index = None + self._event_lists = None + def Handle(self, method, event): - self._events.append(event) + for e in event['params']['value']: + self._events.append(Event(e)) + # Just invalidate our indices rather than trying to be fancy and + # incrementally update. + self._event_msec_index = None + self._event_lists = None def GetEvents(self): return self._events + + def EventsAt(self, msec): + """Gets events active at a timestamp. + + Args: + msec: tracing milliseconds to query. Tracing milliseconds appears to be + since chrome startup (ie, arbitrary epoch). + + Returns: + List of events active at that timestamp. Instantaneous (ie, instant, + sample and counter) events are never included. + TODO(mattcary): currently live objects are included. If this is too big we + may break that out into a separate index. + """ + self._IndexEvents() + idx = bisect.bisect_right(self._event_msec_index, msec) - 1 + if idx < 0: + return [] + events = self._event_lists[idx] + assert events.start_msec <= msec + if not events or events.end_msec < msec: + return [] + return events.event_list + + + def ToJsonDict(self): + return {'events': [e.ToJsonDict() for e in self._events]} + + @classmethod + def FromJsonDict(cls, json_dict): + assert 'events' in json_dict + events = [Event(e) for e in json_dict['events']] + tracing_track = TracingTrack(None) + tracing_track._events = events + return tracing_track + + def _IndexEvents(self): + """Computes index for in-flight events. + + Creates a list of timestamps where events start or end, and tracks the + current set of in-flight events at the instant after each timestamp. To do + this we have to synthesize ending events for complete events, as well as + join and track the nesting of async, flow and other spanning events. + + Events such as instant and counter events that aren't indexable are skipped. + + """ + if self._event_msec_index is not None: + return # Already indexed. + + if not self._events: + raise devtools_monitor.DevToolsConnectionException('No events to index') + + self._event_msec_index = [] + self._event_lists = [] + synthetic_events = [] + for e in self._events: + synthetic_events.extend(e.Synthesize()) + synthetic_events.sort(key=lambda e: e.start_msec) + current_events = set() + next_idx = 0 + spanning_events = self._SpanningEvents() + while next_idx < len(synthetic_events): + current_msec = synthetic_events[next_idx].start_msec + while next_idx < len(synthetic_events): + event = synthetic_events[next_idx] + assert event.IsIndexable() + if event.start_msec > current_msec: + break + matched_event = spanning_events.Match(event) + if matched_event is not None: + event = matched_event + if not event.synthetic and ( + event.end_msec is None or event.end_msec >= current_msec): + current_events.add(event) + next_idx += 1 + current_events -= set([ + e for e in current_events + if e.end_msec is not None and e.end_msec <= current_msec]) + self._event_msec_index.append(current_msec) + self._event_lists.append(self._EventList(current_events)) + if spanning_events.HasPending(): + raise devtools_monitor.DevToolsConnectionException( + 'Pending spanning events: %s' % + '\n'.join([str(e) for e in spanning_events.PendingEvents()])) + + class _SpanningEvents(object): + def __init__(self): + self._duration_stack = [] + self._async_stacks = {} + self._objects = {} + self._MATCH_HANDLER = { + 'B': self._DurationBegin, + 'E': self._DurationEnd, + 'b': self._AsyncStart, + 'e': self._AsyncEnd, + 'S': self._AsyncStart, + 'F': self._AsyncEnd, + 'N': self._ObjectCreated, + 'D': self._ObjectDestroyed, + 'X': self._Ignore, + None: self._Ignore, + } + + def Match(self, event): + return self._MATCH_HANDLER.get( + event.type, self._Unsupported)(event) + + def HasPending(self): + return (self._duration_stack or + self._async_stacks or + self._objects) + + def PendingEvents(self): + return itertools.chain( + (e for e in self._duration_stack), + (o for o in self._objects), + itertools.chain.from_iterable(( + (e for e in s) for s in self._async_stacks.itervalues()))) + + def _AsyncKey(self, event): + return (event.tracing_event['cat'], event.id) + + def _Ignore(self, _event): + return None + + def _Unsupported(self, event): + raise devtools_monitor.DevToolsConnectionException( + 'Unsupported spanning event type: %s' % event) + + def _DurationBegin(self, event): + self._duration_stack.append(event) + return None + + def _DurationEnd(self, event): + if not self._duration_stack: + raise devtools_monitor.DevToolsConnectionException( + 'Unmatched duration end: %s' % event) + start = self._duration_stack.pop() + start.SetClose(event) + return start + + def _AsyncStart(self, event): + key = self._AsyncKey(event) + self._async_stacks.setdefault(key, []).append(event) + return None + + def _AsyncEnd(self, event): + key = self._AsyncKey(event) + if key not in self._async_stacks: + raise devtools_monitor.DevToolsConnectionException( + 'Unmatched async end %s: %s' % (key, event)) + stack = self._async_stacks[key] + start = stack.pop() + if not stack: + del self._async_stacks[key] + start.SetClose(event) + return start + + def _ObjectCreated(self, event): + # The tracing event format has object deletion timestamps being exclusive, + # that is the timestamp for a deletion my equal that of the next create at + # the same address. This asserts that does not happen in practice as it is + # inconvenient to handle that correctly here. + if event.id in self._objects: + raise devtools_monitor.DevToolsConnectionException( + 'Multiple objects at same address: %s, %s' % + (event, self._objects[event.id])) + self._objects[event.id] = event + return None + + def _ObjectDestroyed(self, event): + if event.id not in self._objects: + raise devtools_monitor.DevToolsConnectionException( + 'Missing object creation for %s' % event) + start = self._objects[event.id] + del self._objects[event.id] + start.SetClose(event) + return start + + class _EventList(object): + def __init__(self, events): + self._events = [e for e in events] + if self._events: + self._start_msec = min(e.start_msec for e in self._events) + # Event end times may be changed after this list is created so the end + # can't be cached. + else: + self._start_msec = self._end_msec = None + + @property + def event_list(self): + return self._events + + @property + def start_msec(self): + return self._start_msec + + @property + def end_msec(self): + return max(e.end_msec for e in self._events) + + def __nonzero__(self): + return bool(self._events) + + +class Event(object): + """Wraps a tracing event.""" + CLOSING_EVENTS = {'E': 'B', + 'e': 'b', + 'F': 'S', + 'D': 'N'} + def __init__(self, tracing_event, synthetic=False): + """Creates Event. + + Intended to be created only by TracingTrack. + + Args: + tracing_event: JSON tracing event, as defined in https://goo.gl/Qabkqk. + synthetic: True if the event is synthetic. This is only used for indexing + internal to TracingTrack. + """ + if not synthetic and tracing_event['ph'] in ['s', 't', 'f']: + raise devtools_monitor.DevToolsConnectionException( + 'Unsupported event: %s' % tracing_event) + if not synthetic and tracing_event['ph'] in ['p']: + raise devtools_monitor.DevToolsConnectionException( + 'Deprecated event: %s' % tracing_event) + + self._tracing_event = tracing_event + # Note tracing event times are in microseconds. + self._start_msec = tracing_event['ts'] / 1000.0 + self._end_msec = None + self._synthetic = synthetic + if self.type == 'X': + # Some events don't have a duration. + duration = (tracing_event['dur'] + if 'dur' in tracing_event else tracing_event['tdur']) + self._end_msec = self.start_msec + duration / 1000.0 + + @property + def start_msec(self): + return self._start_msec + + @property + def end_msec(self): + return self._end_msec + + @property + def type(self): + if self._synthetic: + return None + return self._tracing_event['ph'] + + @property + def args(self): + return self._tracing_event.get('args', {}) + + @property + def id(self): + return self._tracing_event.get('id') + + @property + def tracing_event(self): + return self._tracing_event + + @property + def synthetic(self): + return self._synthetic + + def __str__(self): + return ''.join([str(self._tracing_event), + '[%s,%s]' % (self.start_msec, self.end_msec)]) + + def IsIndexable(self): + """True iff the event can be indexed by time.""" + return self._synthetic or self.type not in [ + 'I', 'P', 'c', 'C', + 'n', 'T', 'p', # TODO(mattcary): ?? instant types of async events. + 'O', # TODO(mattcary): ?? object snapshot + ] + + def Synthesize(self): + """Expand into synthetic events. + + Returns: + A list of events, possibly some synthetic, whose start times are all + interesting for purposes of indexing. If the event is not indexable the + set may be empty. + """ + if not self.IsIndexable(): + return [] + if self.type == 'X': + # Tracing event timestamps are microseconds! + return [self, Event({'ts': self.end_msec * 1000}, synthetic=True)] + return [self] + + def SetClose(self, closing): + """Close a spanning event. + + Args: + closing: The closing event. + + Raises: + devtools_monitor.DevToolsConnectionException if closing can't property + close this event. + """ + if self.type != self.CLOSING_EVENTS.get(closing.type): + raise devtools_monitor.DevToolsConnectionException( + 'Bad closing: %s --> %s' % (self, closing)) + if self.type in ['b', 'S'] and ( + self.tracing_event['cat'] != closing.tracing_event['cat'] or + self.id != closing.id): + raise devtools_monitor.DevToolsConnectionException( + 'Bad async closing: %s --> %s' % (self, closing)) + self._end_msec = closing.start_msec + if 'args' in closing.tracing_event: + self.tracing_event.setdefault( + 'args', {}).update(closing.tracing_event['args']) + + def ToJsonDict(self): + return self._tracing_event + + @classmethod + def FromJsonDict(cls, json_dict): + return Event(json_dict)
diff --git a/tools/android/loading/tracing_driver.py b/tools/android/loading/tracing_driver.py deleted file mode 100755 index c62e870..0000000 --- a/tools/android/loading/tracing_driver.py +++ /dev/null
@@ -1,49 +0,0 @@ -#! /usr/bin/python -# Copyright 2016 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -"""Drive TracingConnection""" - -import argparse -import json -import logging -import os.path -import sys - -_SRC_DIR = os.path.abspath(os.path.join( - os.path.dirname(__file__), '..', '..', '..')) - -sys.path.append(os.path.join(_SRC_DIR, 'third_party', 'catapult', 'devil')) -from devil.android import device_utils - -sys.path.append(os.path.join(_SRC_DIR, 'build', 'android')) -import device_setup -import page_track -import tracing - - -def main(): - logging.basicConfig(level=logging.INFO) - parser = argparse.ArgumentParser() - parser.add_argument('--url', required=True) - parser.add_argument('--output', required=True) - args = parser.parse_args() - url = args.url - if not url.startswith('http'): - url = 'http://' + url - device = device_utils.DeviceUtils.HealthyDevices()[0] - with file(args.output, 'w') as output, \ - file(args.output + '.page', 'w') as page_output, \ - device_setup.DeviceConnection(device) as connection: - track = tracing.TracingTrack(connection, fetch_stream=False) - page = page_track.PageTrack(connection) - connection.SetUpMonitoring() - connection.SendAndIgnoreResponse('Page.navigate', {'url': url}) - connection.StartMonitoring() - json.dump(page.GetEvents(), page_output, sort_keys=True, indent=2) - json.dump(track.GetEvents(), output, sort_keys=True, indent=2) - - -if __name__ == '__main__': - main()
diff --git a/tools/android/loading/tracing_unittest.py b/tools/android/loading/tracing_unittest.py new file mode 100644 index 0000000..77116fe --- /dev/null +++ b/tools/android/loading/tracing_unittest.py
@@ -0,0 +1,209 @@ +# Copyright 2016 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import logging +import unittest + +import devtools_monitor + +from tracing import (Event, TracingTrack) + + +class TracingTrackTestCase(unittest.TestCase): + _MIXED_EVENTS = [ + {'ts': 3, 'ph': 'N', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'X', 'dur': 1, 'args': {'name': 'B'}}, + {'ts': 7, 'ph': 'D', 'id': 1}, + {'ts': 10, 'ph': 'B', 'args': {'name': 'D'}}, + {'ts': 10, 'ph': 'b', 'cat': 'X', 'id': 1, 'args': {'name': 'C'}}, + {'ts': 11, 'ph': 'e', 'cat': 'X', 'id': 1}, + {'ts': 12, 'ph': 'E'}, + {'ts': 12, 'ph': 'N', 'id': 1, 'args': {'name': 'E'}}, + {'ts': 13, 'ph': 'b', 'cat': 'X', 'id': 2, 'args': {'name': 'F'}}, + {'ts': 14, 'ph': 'e', 'cat': 'X', 'id': 2}, + {'ts': 15, 'ph': 'D', 'id': 1}] + + def setUp(self): + self.track = TracingTrack(None) + + def EventToMicroseconds(self, event): + if 'ts' in event: + event['ts'] *= 1000 + if 'dur' in event: + event['dur'] *= 1000 + return event + + def CheckTrack(self, timestamp, names): + self.assertEqual( + set((e.args['name'] for e in self.track.EventsAt(timestamp))), + set(names)) + + def CheckIntervals(self, events): + """All tests should produce the following sequence of intervals, each + identified by a 'name' in the event args. + + Timestamp + 3 | A + 4 | + 5 | | B + 6 | + 7 + .. + 10 | | C, D + 11 | + 12 | E + 13 | | F + 14 | + """ + self.track.Handle('Tracing.dataCollected', + {'params': {'value': [self.EventToMicroseconds(e) + for e in events]}}) + self.CheckTrack(0, '') + self.CheckTrack(2, '') + self.CheckTrack(3, 'A') + self.CheckTrack(4, 'A') + self.CheckTrack(5, 'AB') + self.CheckTrack(6, 'A') + self.CheckTrack(7, '') + self.CheckTrack(9, '') + self.CheckTrack(10, 'CD') + self.CheckTrack(11, 'D') + self.CheckTrack(12, 'E') + self.CheckTrack(13, 'EF') + self.CheckTrack(14, 'E') + self.CheckTrack(15, '') + self.CheckTrack(100, '') + + def testComplete(self): + # These are deliberately out of order. + self.CheckIntervals([ + {'ts': 5, 'ph': 'X', 'dur': 1, 'args': {'name': 'B'}}, + {'ts': 3, 'ph': 'X', 'dur': 4, 'args': {'name': 'A'}}, + {'ts': 10, 'ph': 'X', 'dur': 1, 'args': {'name': 'C'}}, + {'ts': 10, 'ph': 'X', 'dur': 2, 'args': {'name': 'D'}}, + {'ts': 13, 'ph': 'X', 'dur': 1, 'args': {'name': 'F'}}, + {'ts': 12, 'ph': 'X', 'dur': 3, 'args': {'name': 'E'}}]) + + def testDuration(self): + self.CheckIntervals([ + {'ts': 3, 'ph': 'B', 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'B', 'args': {'name': 'B'}}, + {'ts': 6, 'ph': 'E'}, + {'ts': 7, 'ph': 'E'}, + # Since async intervals aren't named and must be nested, we fudge the + # beginning of D by a tenth to ensure it's consistently detected as the + # outermost event. + {'ts': 9.9, 'ph': 'B', 'args': {'name': 'D'}}, + {'ts': 10, 'ph': 'B', 'args': {'name': 'C'}}, + {'ts': 11, 'ph': 'E'}, + # End of D. As end times are exclusive this should not conflict with the + # start of E. + {'ts': 12, 'ph': 'E'}, + {'ts': 12, 'ph': 'B', 'args': {'name': 'E'}}, + {'ts': 13, 'ph': 'B', 'args': {'name': 'F'}}, + {'ts': 14, 'ph': 'E'}, + {'ts': 15, 'ph': 'E'}]) + + def testBadDurationExtraBegin(self): + self.assertRaises(devtools_monitor.DevToolsConnectionException, + self.CheckIntervals, + [{'ts': 3, 'ph': 'B'}, + {'ts': 4, 'ph': 'B'}, + {'ts': 5, 'ph': 'E'}]) + + def testBadDurationExtraEnd(self): + self.assertRaises(devtools_monitor.DevToolsConnectionException, + self.CheckIntervals, + [{'ts': 3, 'ph': 'B'}, + {'ts': 4, 'ph': 'E'}, + {'ts': 5, 'ph': 'E'}]) + + def testAsync(self): + self.CheckIntervals([ + # A, B and F have the same category/id (so that A & B nest); C-E do not. + {'ts': 3, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'B'}}, + # Not indexable. + {'ts': 4, 'ph': 'n', 'cat': 'A', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 6, 'ph': 'e', 'cat': 'A', 'id': 1}, + {'ts': 7, 'ph': 'e', 'cat': 'A', 'id': 1}, + {'ts': 10, 'ph': 'b', 'cat': 'B', 'id': 2, 'args': {'name': 'D'}}, + {'ts': 10, 'ph': 'b', 'cat': 'B', 'id': 3, 'args': {'name': 'C'}}, + {'ts': 11, 'ph': 'e', 'cat': 'B', 'id': 3}, + {'ts': 12, 'ph': 'e', 'cat': 'B', 'id': 2}, + {'ts': 12, 'ph': 'b', 'cat': 'A', 'id': 2, 'args': {'name': 'E'}}, + {'ts': 13, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'F'}}, + {'ts': 14, 'ph': 'e', 'cat': 'A', 'id': 1}, + {'ts': 15, 'ph': 'e', 'cat': 'A', 'id': 2}]) + + def testBadAsyncIdMismatch(self): + self.assertRaises( + devtools_monitor.DevToolsConnectionException, + self.CheckIntervals, + [{'ts': 3, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'B'}}, + {'ts': 6, 'ph': 'e', 'cat': 'A', 'id': 2}, + {'ts': 7, 'ph': 'e', 'cat': 'A', 'id': 1}]) + + def testBadAsyncExtraBegin(self): + self.assertRaises( + devtools_monitor.DevToolsConnectionException, + self.CheckIntervals, + [{'ts': 3, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'B'}}, + {'ts': 6, 'ph': 'e', 'cat': 'A', 'id': 1}]) + + def testBadAsyncExtraEnd(self): + self.assertRaises( + devtools_monitor.DevToolsConnectionException, + self.CheckIntervals, + [{'ts': 3, 'ph': 'b', 'cat': 'A', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'e', 'cat': 'A', 'id': 1}, + {'ts': 6, 'ph': 'e', 'cat': 'A', 'id': 1}]) + + def testObject(self): + # A and E share ids, which is okay as their scopes are disjoint. + self.CheckIntervals([ + {'ts': 3, 'ph': 'N', 'id': 1, 'args': {'name': 'A'}}, + {'ts': 5, 'ph': 'N', 'id': 2, 'args': {'name': 'B'}}, + {'ts': 6, 'ph': 'D', 'id': 2}, + {'ts': 6, 'ph': 'O', 'id': 2}, # Ignored. + {'ts': 7, 'ph': 'D', 'id': 1}, + {'ts': 10, 'ph': 'N', 'id': 3, 'args': {'name': 'D'}}, + {'ts': 10, 'ph': 'N', 'id': 4, 'args': {'name': 'C'}}, + {'ts': 11, 'ph': 'D', 'id': 4}, + {'ts': 12, 'ph': 'D', 'id': 3}, + {'ts': 12, 'ph': 'N', 'id': 1, 'args': {'name': 'E'}}, + {'ts': 13, 'ph': 'N', 'id': 5, 'args': {'name': 'F'}}, + {'ts': 14, 'ph': 'D', 'id': 5}, + {'ts': 15, 'ph': 'D', 'id': 1}]) + + def testMixed(self): + # A and E are objects, B complete, D a duration, and C and F async. + self.CheckIntervals(self._MIXED_EVENTS) + + def testEventSerialization(self): + for e in self._MIXED_EVENTS: + event = Event(e) + json_dict = event.ToJsonDict() + deserialized_event = Event.FromJsonDict(json_dict) + self.assertEquals( + event.tracing_event, deserialized_event.tracing_event) + + def testTracingTrackSerialization(self): + events = self._MIXED_EVENTS + self.track.Handle('Tracing.dataCollected', + {'params': {'value': [self.EventToMicroseconds(e) + for e in events]}}) + json_dict = self.track.ToJsonDict() + self.assertTrue('events' in json_dict) + deserialized_track = TracingTrack.FromJsonDict(json_dict) + self.assertEquals( + len(self.track._events), len(deserialized_track._events)) + for (e1, e2) in zip(self.track._events, deserialized_track._events): + self.assertEquals(e1.tracing_event, e2.tracing_event) + + +if __name__ == '__main__': + unittest.main()
diff --git a/tools/md_browser/header.html b/tools/md_browser/header.html index 939eb943..1493ec3 100644 --- a/tools/md_browser/header.html +++ b/tools/md_browser/header.html
@@ -1,6 +1,7 @@ <!DOCTYPE HTML PUBLIC "-//W3CDTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html class="doc-page"> <head> +<meta charset="UTF-8" /> <link rel="stylesheet" type="text/css" href="/doc.css" /> </head> <body>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 999559c..f650bb60 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -3479,6 +3479,21 @@ </summary> </histogram> +<histogram name="BrotliFilter.CompressionPercent" units="%"> + <owner>eustas@chromium.org</owner> + <summary>Compressed/Decompressed size ratio.</summary> +</histogram> + +<histogram name="BrotliFilter.Status" enum="BrotliFilterDecodingStatus"> + <owner>eustas@chromium.org</owner> + <summary>The final state of BrotliFilter.</summary> +</histogram> + +<histogram name="BrotliFilter.UsedMemoryKB" units="KiB"> + <owner>eustas@chromium.org</owner> + <summary>Maximal amount of memory allocated by decoder.</summary> +</histogram> + <histogram name="BrowserRenderProcessHost.ChildCrashes" enum="RendererType"> <owner>wfh@chromium.org</owner> <summary>Count of renderer process crashes grouped by type.</summary> @@ -26342,6 +26357,49 @@ </summary> </histogram> +<histogram name="Net.RequestTime2.ErrAborted.HttpScheme" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + ERR_ABORTED when the request's scheme is http/s. + </summary> +</histogram> + +<histogram name="Net.RequestTime2.ErrAborted.NetworkContent" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + ERR_ABORTED when the requests TotalReceivedBytes() > 0. + </summary> +</histogram> + +<histogram name="Net.RequestTime2.ErrAborted.NoBytesRead" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + ERR_ABORTED when the requests TotalReceivedBytes() = 0 and + received_response_content_length() = 0. + </summary> +</histogram> + +<histogram name="Net.RequestTime2.ErrAborted.NoNetworkContent.CachedContent" + units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + ERR_ABORTED when the requests TotalReceivedBytes() = 0 and + received_response_content_length() > 0. + </summary> +</histogram> + +<histogram name="Net.RequestTime2.ErrAborted.NonHttpScheme" units="ms"> + <owner>csharrison@chromium.org</owner> + <summary> + The amount of time between request initiation and request completion for + ERR_ABORTED when the request's scheme is not http/s. + </summary> +</histogram> + <histogram name="Net.ResourceLoader.ReadDeferral" units="ms"> <owner>clamy@chromium.org</owner> <summary> @@ -57954,6 +58012,12 @@ <int value="3" label="HTTP_STREAM_FACTORY_IMPL_JOB_MAIN"/> </enum> +<enum name="BrotliFilterDecodingStatus" type="int"> + <int value="0" label="In progress"/> + <int value="1" label="Done"/> + <int value="2" label="Error"/> +</enum> + <enum name="BubbleType" type="int"> <int value="0" label="Unknown Bubble"/> <int value="1" label="Mock Bubble"/> @@ -76343,6 +76407,7 @@ <int value="242" label="MSG"/> <int value="243" label="EML"/> <int value="244" label="RTF"/> + <int value="245" label="VHDX"/> </enum> <enum name="SBClientDownloadIsSignedBinary" type="int">
diff --git a/tools/perf/docs/perf_bot_sheriffing.md b/tools/perf/docs/perf_bot_sheriffing.md index 99cee30..ca8df2a 100644 --- a/tools/perf/docs/perf_bot_sheriffing.md +++ b/tools/perf/docs/perf_bot_sheriffing.md
@@ -20,8 +20,8 @@ Everyone can view the chromium.perf waterfall at https://build.chromium.org/p/chromium.perf/, but for Googlers it is recommended -that you use the url -**https://uberchromegw.corp.google.com/i/chromium.perf/** instead. The reason +that you use the url [**https://uberchromegw.corp.google.com/i/chromium.perf/**] +(https://uberchromegw.corp.google.com/i/chromium.perf/) instead. The reason for this is that in order to make the performance tests as realistic as possible, the chromium.perf waterfall runs release official builds of Chrome. But the logs from release official builds may leak info from our partners that
diff --git a/tools/telemetry/telemetry/timeline/tracing_config.py b/tools/telemetry/telemetry/timeline/tracing_config.py index 23bc0c6..365f71d 100644 --- a/tools/telemetry/telemetry/timeline/tracing_config.py +++ b/tools/telemetry/telemetry/timeline/tracing_config.py
@@ -22,6 +22,30 @@ } +class MemoryDumpConfig(object): + """Stores the triggers for memory dumps in tracing config.""" + def __init__(self): + self._triggers = [] + + def AddTrigger(self, mode, periodic_interval_ms): + """Adds a new trigger to config. + + Args: + periodic_interval_ms: Dump time period in milliseconds. + level_of_detail: Memory dump level of detail string. + Valid arguments are "light" and "detailed". + """ + assert mode in ['light', 'detailed'] + assert periodic_interval_ms > 0 + self._triggers.append({'mode': mode, + 'periodic_interval_ms': periodic_interval_ms}) + + def GetDictForChromeTracing(self): + """Returns the dump config as dictionary for chrome tracing.""" + # An empty trigger list would mean no periodic memory dumps. + return {'memory_dump_config': {'triggers': self._triggers}} + + class TracingConfig(object): """Tracing config is the configuration for Chrome tracing. @@ -62,6 +86,7 @@ # Tracing category filter. self._tracing_category_filter = ( tracing_category_filter.TracingCategoryFilter()) + self._memory_dump_config = None @property def tracing_category_filter(self): @@ -71,6 +96,8 @@ result = {} result.update(self.GetDictForChromeTracing()) result.update(self._tracing_category_filter.GetDictForChromeTracing()) + if self._memory_dump_config: + result.update(self._memory_dump_config.GetDictForChromeTracing()) return json.dumps(result, sort_keys=True) def SetNoOverheadFilter(self): @@ -110,6 +137,13 @@ raise TypeError( 'Must pass SetTracingCategoryFilter a TracingCategoryFilter instance') + def SetMemoryDumpConfig(self, dump_config): + if isinstance(dump_config, MemoryDumpConfig): + self._memory_dump_config = dump_config + else: + raise TypeError( + 'Must pass SetMemoryDumpConfig a MemoryDumpConfig instance') + # Trace Options @property def record_mode(self):
diff --git a/tools/telemetry/telemetry/timeline/tracing_config_unittest.py b/tools/telemetry/telemetry/timeline/tracing_config_unittest.py index dc79c56b..06578bc 100644 --- a/tools/telemetry/telemetry/timeline/tracing_config_unittest.py +++ b/tools/telemetry/telemetry/timeline/tracing_config_unittest.py
@@ -35,3 +35,30 @@ '"synthetic_delays": ["DELAY(7;foo)"]' '}', config_string) + + def testMemoryDumpConfigFormat(self): + config = tracing_config.TracingConfig() + dump_config = tracing_config.MemoryDumpConfig() + config.SetMemoryDumpConfig(dump_config) + self.assertEquals( + '{' + '"memory_dump_config": {"triggers": []}, ' + '"record_mode": "record-as-much-as-possible"' + '}', + config.GetChromeTraceConfigJsonString()) + + dump_config.AddTrigger("light", 250) + dump_config.AddTrigger("detailed", 2000) + config.SetMemoryDumpConfig(dump_config) + self.assertEquals( + '{' + '"memory_dump_config": ' + '{' + '"triggers": [' + '{"mode": "light", "periodic_interval_ms": 250}, ' + '{"mode": "detailed", "periodic_interval_ms": 2000}' + ']' + '}, ' + '"record_mode": "record-as-much-as-possible"' + '}', + config.GetChromeTraceConfigJsonString())
diff --git a/ui/events/cocoa/events_mac.mm b/ui/events/cocoa/events_mac.mm index 79beaf3..003b880 100644 --- a/ui/events/cocoa/events_mac.mm +++ b/ui/events/cocoa/events_mac.mm
@@ -178,24 +178,20 @@ return 0; } -float GetTouchRadiusX(const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); - return 0.f; -} - -float GetTouchRadiusY(const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); - return 0.f; -} - float GetTouchAngle(const base::NativeEvent& native_event) { NOTIMPLEMENTED(); return 0.f; } -float GetTouchForce(const base::NativeEvent& native_event) { +PointerDetails GetTouchPointerDetailsFromNative( + const base::NativeEvent& native_event) { NOTIMPLEMENTED(); - return 0.f; + return PointerDetails(EventPointerType::POINTER_TYPE_UNKNOWN, + /* radius_x */ 1.0, + /* radius_y */ 1.0, + /* force */ 0.f, + /* tilt_x */ 0.f, + /* tilt_y */ 0.f); } bool GetScrollOffsets(const base::NativeEvent& native_event,
diff --git a/ui/events/event.cc b/ui/events/event.cc index f4cf7cf..626c52c 100644 --- a/ui/events/event.cc +++ b/ui/events/event.cc
@@ -524,12 +524,7 @@ rotation_angle_(GetTouchAngle(native_event)), may_cause_scrolling_(false), should_remove_native_touch_id_mapping_(false), - pointer_details_(PointerDetails(EventPointerType::POINTER_TYPE_TOUCH, - GetTouchRadiusX(native_event), - GetTouchRadiusY(native_event), - GetTouchForce(native_event), - /* tilt_x */ 0.0f, - /* tilt_y */ 0.0f)) { + pointer_details_(GetTouchPointerDetailsFromNative(native_event)) { latency()->AddLatencyNumberWithTimestamp( INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0, 0, base::TimeTicks::FromInternalValue(time_stamp().ToInternalValue()), 1);
diff --git a/ui/events/event_utils.h b/ui/events/event_utils.h index 54081a5c..4a8e163 100644 --- a/ui/events/event_utils.h +++ b/ui/events/event_utils.h
@@ -115,6 +115,10 @@ void ReleaseCopiedNativeEvent( const base::NativeEvent& native_event); +// Returns the detailed pointer information for touch events. +EVENTS_EXPORT PointerDetails +GetTouchPointerDetailsFromNative(const base::NativeEvent& native_event); + // Gets the touch id from a native event. EVENTS_EXPORT int GetTouchId(const base::NativeEvent& native_event); @@ -122,16 +126,9 @@ EVENTS_EXPORT void ClearTouchIdIfReleased( const base::NativeEvent& native_event); -// Gets the radius along the X/Y axis from a native event. Default is 1.0. -EVENTS_EXPORT float GetTouchRadiusX(const base::NativeEvent& native_event); -EVENTS_EXPORT float GetTouchRadiusY(const base::NativeEvent& native_event); - // Gets the angle of the major axis away from the X axis. Default is 0.0. EVENTS_EXPORT float GetTouchAngle(const base::NativeEvent& native_event); -// Gets the force from a native_event. Normalized to be [0, 1]. Default is 0.0. -EVENTS_EXPORT float GetTouchForce(const base::NativeEvent& native_event); - // Gets the fling velocity from a native event. is_cancel is set to true if // this was a tap down, intended to stop an ongoing fling. EVENTS_EXPORT bool GetFlingData(const base::NativeEvent& native_event,
diff --git a/ui/events/events_default.cc b/ui/events/events_default.cc index 7d55e8e..b6bf22e 100644 --- a/ui/events/events_default.cc +++ b/ui/events/events_default.cc
@@ -96,18 +96,12 @@ return event->touch_id(); } -float GetTouchRadiusX(const base::NativeEvent& native_event) { +PointerDetails GetTouchPointerDetailsFromNative( + const base::NativeEvent& native_event) { const ui::TouchEvent* event = static_cast<const ui::TouchEvent*>(native_event); DCHECK(event->IsTouchEvent()); - return event->pointer_details().radius_x(); -} - -float GetTouchRadiusY(const base::NativeEvent& native_event) { - const ui::TouchEvent* event = - static_cast<const ui::TouchEvent*>(native_event); - DCHECK(event->IsTouchEvent()); - return event->pointer_details().radius_y(); + return event->pointer_details(); } float GetTouchAngle(const base::NativeEvent& native_event) { @@ -117,13 +111,6 @@ return event->rotation_angle(); } -float GetTouchForce(const base::NativeEvent& native_event) { - const ui::TouchEvent* event = - static_cast<const ui::TouchEvent*>(native_event); - DCHECK(event->IsTouchEvent()); - return event->pointer_details().force(); -} - bool GetScrollOffsets(const base::NativeEvent& native_event, float* x_offset, float* y_offset,
diff --git a/ui/events/events_stub.cc b/ui/events/events_stub.cc index edd7765..a334311 100644 --- a/ui/events/events_stub.cc +++ b/ui/events/events_stub.cc
@@ -86,24 +86,20 @@ return 0; } -float GetTouchRadiusX(const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); - return 0.f; -} - -float GetTouchRadiusY(const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); - return 0.f; -} - float GetTouchAngle(const base::NativeEvent& native_event) { NOTIMPLEMENTED(); return 0.f; } -float GetTouchForce(const base::NativeEvent& native_event) { +PointerDetails GetTouchPointerDetailsFromNative( + const base::NativeEvent& native_event) { NOTIMPLEMENTED(); - return 0.f; + return PointerDetails(EventPointerType::POINTER_TYPE_UNKNOWN, + /* radius_x */ 1.0, + /* radius_y */ 1.0, + /* force */ 0.f, + /* tilt_x */ 0.f, + /* tilt_y */ 0.f); } bool GetScrollOffsets(const base::NativeEvent& native_event,
diff --git a/ui/events/win/events_win.cc b/ui/events/win/events_win.cc index 20c6e61..e4573312 100644 --- a/ui/events/win/events_win.cc +++ b/ui/events/win/events_win.cc
@@ -322,24 +322,20 @@ return 0; } -float GetTouchRadiusX(const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); - return 1.0; -} - -float GetTouchRadiusY(const base::NativeEvent& native_event) { - NOTIMPLEMENTED(); - return 1.0; -} - float GetTouchAngle(const base::NativeEvent& native_event) { NOTIMPLEMENTED(); return 0.0; } -float GetTouchForce(const base::NativeEvent& native_event) { +PointerDetails GetTouchPointerDetailsFromNative( + const base::NativeEvent& native_event) { NOTIMPLEMENTED(); - return 0.0; + return PointerDetails(EventPointerType::POINTER_TYPE_TOUCH, + /* radius_x */ 1.0, + /* radius_y */ 1.0, + /* force */ 0.f, + /* tilt_x */ 0.f, + /* tilt_y */ 0.f); } bool GetScrollOffsets(const base::NativeEvent& native_event,
diff --git a/ui/events/x/events_x.cc b/ui/events/x/events_x.cc index 647b55b..c1fc65a 100644 --- a/ui/events/x/events_x.cc +++ b/ui/events/x/events_x.cc
@@ -154,20 +154,18 @@ return GetTouchIdFromXEvent(*native_event); } -float GetTouchRadiusX(const base::NativeEvent& native_event) { - return GetTouchRadiusXFromXEvent(*native_event); -} - -float GetTouchRadiusY(const base::NativeEvent& native_event) { - return GetTouchRadiusYFromXEvent(*native_event); -} - float GetTouchAngle(const base::NativeEvent& native_event) { return GetTouchAngleFromXEvent(*native_event); } -float GetTouchForce(const base::NativeEvent& native_event) { - return GetTouchForceFromXEvent(*native_event); +PointerDetails GetTouchPointerDetailsFromNative( + const base::NativeEvent& native_event) { + return PointerDetails(EventPointerType::POINTER_TYPE_TOUCH, + GetTouchRadiusXFromXEvent(*native_event), + GetTouchRadiusYFromXEvent(*native_event), + GetTouchForceFromXEvent(*native_event), + /* tilt_x */ 0.f, + /* tilt_y */ 0.f); } bool GetScrollOffsets(const base::NativeEvent& native_event,
diff --git a/ui/events/x/events_x_unittest.cc b/ui/events/x/events_x_unittest.cc index c020665..faac0e6 100644 --- a/ui/events/x/events_x_unittest.cc +++ b/ui/events/x/events_x_unittest.cc
@@ -239,9 +239,11 @@ EXPECT_EQ(ui::ET_TOUCH_PRESSED, ui::EventTypeFromNative(scoped_xevent)); EXPECT_EQ("10,10", ui::EventLocationFromNative(scoped_xevent).ToString()); EXPECT_EQ(GetTouchId(scoped_xevent), 0); - EXPECT_EQ(GetTouchRadiusX(scoped_xevent), 10); EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.15f); - EXPECT_FLOAT_EQ(GetTouchForce(scoped_xevent), 0.1f); + PointerDetails pointer_details = + GetTouchPointerDetailsFromNative(scoped_xevent); + EXPECT_FLOAT_EQ(pointer_details.radius_x(), 10.0f); + EXPECT_FLOAT_EQ(pointer_details.force(), 0.1f); // Touch update, with new orientation info. valuators.clear(); @@ -252,9 +254,10 @@ EXPECT_EQ(ui::ET_TOUCH_MOVED, ui::EventTypeFromNative(scoped_xevent)); EXPECT_EQ("20,20", ui::EventLocationFromNative(scoped_xevent).ToString()); EXPECT_EQ(GetTouchId(scoped_xevent), 0); - EXPECT_EQ(GetTouchRadiusX(scoped_xevent), 10); EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.25f); - EXPECT_FLOAT_EQ(GetTouchForce(scoped_xevent), 0.1f); + pointer_details = GetTouchPointerDetailsFromNative(scoped_xevent); + EXPECT_FLOAT_EQ(pointer_details.radius_x(), 10.0f); + EXPECT_FLOAT_EQ(pointer_details.force(), 0.1f); // Another touch with tracking id 6, touch id 1. valuators.clear(); @@ -267,9 +270,10 @@ EXPECT_EQ(ui::ET_TOUCH_PRESSED, ui::EventTypeFromNative(scoped_xevent)); EXPECT_EQ("200,200", ui::EventLocationFromNative(scoped_xevent).ToString()); EXPECT_EQ(GetTouchId(scoped_xevent), 1); - EXPECT_EQ(GetTouchRadiusX(scoped_xevent), 50); EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.45f); - EXPECT_FLOAT_EQ(GetTouchForce(scoped_xevent), 0.5f); + pointer_details = GetTouchPointerDetailsFromNative(scoped_xevent); + EXPECT_FLOAT_EQ(pointer_details.radius_x(), 50.0f); + EXPECT_FLOAT_EQ(pointer_details.force(), 0.5f); // Touch with tracking id 5 should have old radius/angle value and new pressue // value. @@ -280,9 +284,10 @@ EXPECT_EQ(ui::ET_TOUCH_RELEASED, ui::EventTypeFromNative(scoped_xevent)); EXPECT_EQ("30,30", ui::EventLocationFromNative(scoped_xevent).ToString()); EXPECT_EQ(GetTouchId(scoped_xevent), 0); - EXPECT_EQ(GetTouchRadiusX(scoped_xevent), 10); EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.25f); - EXPECT_FLOAT_EQ(GetTouchForce(scoped_xevent), 0.05f); + pointer_details = GetTouchPointerDetailsFromNative(scoped_xevent); + EXPECT_FLOAT_EQ(pointer_details.radius_x(), 10.0f); + EXPECT_FLOAT_EQ(pointer_details.force(), 0.05f); // Touch with tracking id 6 should have old angle/pressure value and new // radius value. @@ -293,9 +298,10 @@ EXPECT_EQ(ui::ET_TOUCH_RELEASED, ui::EventTypeFromNative(scoped_xevent)); EXPECT_EQ("200,200", ui::EventLocationFromNative(scoped_xevent).ToString()); EXPECT_EQ(GetTouchId(scoped_xevent), 1); - EXPECT_EQ(GetTouchRadiusX(scoped_xevent), 25); EXPECT_FLOAT_EQ(GetTouchAngle(scoped_xevent), 0.45f); - EXPECT_FLOAT_EQ(GetTouchForce(scoped_xevent), 0.5f); + pointer_details = GetTouchPointerDetailsFromNative(scoped_xevent); + EXPECT_FLOAT_EQ(pointer_details.radius_x(), 25.0f); + EXPECT_FLOAT_EQ(pointer_details.force(), 0.5f); } int GetTouchIdForTrackingId(uint32_t tracking_id) {
diff --git a/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc b/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc index f0647eb7..72a2c14 100644 --- a/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc +++ b/ui/ozone/platform/drm/gpu/drm_thread_message_proxy.cc
@@ -51,10 +51,10 @@ OnRemoveGraphicsDevice) IPC_MESSAGE_HANDLER(OzoneGpuMsg_GetHDCPState, OnGetHDCPState) IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetHDCPState, OnSetHDCPState) - IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetGammaRamp, OnSetGammaRamp); + IPC_MESSAGE_HANDLER(OzoneGpuMsg_SetGammaRamp, OnSetGammaRamp) IPC_MESSAGE_HANDLER(OzoneGpuMsg_CheckOverlayCapabilities, OnCheckOverlayCapabilities) - IPC_MESSAGE_UNHANDLED(handled = false); + IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled;
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index d16553b..10b2cd9 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -679,7 +679,7 @@ if (event->type() == ui::ET_TOUCH_PRESSED) { MenuPart part = GetMenuPart(source, event->location()); if (part.type == MenuPart::NONE) { - RepostEvent(source, event); + RepostEventAndCancel(source, event); event->SetHandled(); } } @@ -1001,36 +1001,8 @@ // then use this to figure out if this menu was finished with the same click // which is sent to it thereafter. closing_event_time_ = event->time_stamp(); - - // Mouse wasn't pressed over any menu, or the active menu, cancel. - -#if defined(OS_WIN) - // We're going to close and we own the mouse capture. We need to repost the - // mouse down, otherwise the window the user clicked on won't get the event. - RepostEvent(source, event); -#endif - - // And close. - ExitType exit_type = EXIT_ALL; - if (!menu_stack_.empty()) { - // We're running nested menus. Only exit all if the mouse wasn't over one - // of the menus from the last run. - gfx::Point screen_loc(event->location()); - View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); - MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( - menu_stack_.back().first.item, screen_loc); - if (last_part.type != MenuPart::NONE) - exit_type = EXIT_OUTERMOST; - } - Cancel(exit_type); - -#if defined(OS_CHROMEOS) - // We're going to exit the menu and want to repost the event so that is - // is handled normally after the context menu has exited. We call - // RepostEvent after Cancel so that mouse capture has been released so - // that finding the event target is unaffected by the current capture. - RepostEvent(source, event); -#endif + // Event wasn't pressed over any menu, or the active menu, cancel. + RepostEventAndCancel(source, event); // Do not repost events for Linux Aura because this behavior is more // consistent with the behavior of other Linux apps. return; @@ -2188,7 +2160,10 @@ } void MenuController::RepostEvent(SubmenuView* source, - const ui::LocatedEvent* event) { + const ui::LocatedEvent* event, + const gfx::Point& screen_loc, + gfx::NativeView native_view, + gfx::NativeWindow window) { if (!event->IsMouseEvent() && !event->IsTouchEvent()) { // TODO(rbyers): Gesture event repost is tricky to get right // crbug.com/170987. @@ -2208,15 +2183,9 @@ state_.item->GetRootMenuItem()->GetSubmenu()->ReleaseCapture(); #endif - gfx::Point screen_loc(event->location()); - View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); - gfx::NativeView native_view = source->GetWidget()->GetNativeView(); if (!native_view) return; - gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); - gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); - #if defined(OS_WIN) gfx::Point screen_loc_pixels = gfx::win::DIPToScreenPoint(screen_loc); HWND target_window = ::WindowFromPoint(screen_loc_pixels.ToPOINT()); @@ -2294,6 +2263,47 @@ MenuMessageLoop::RepostEventToWindow(event, window, screen_loc); } +void MenuController::RepostEventAndCancel(SubmenuView* source, + const ui::LocatedEvent* event) { + // Cancel can lead to the deletion |source| so we save the view and window to + // be used when reposting the event. + gfx::Point screen_loc(event->location()); + View::ConvertPointToScreen(source->GetScrollViewContainer(), &screen_loc); + gfx::NativeView native_view = source->GetWidget()->GetNativeView(); + gfx::NativeWindow window = nullptr; + if (native_view) { + gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); + window = screen->GetWindowAtScreenPoint(screen_loc); + } + +#if defined(OS_WIN) + // We're going to close and we own the event capture. We need to repost the + // event, otherwise the window the user clicked on won't get the event. + RepostEvent(source, event, screen_loc, native_view, window); +#endif + + // Determine target to see if a complete or partial close of the menu should + // occur. + ExitType exit_type = EXIT_ALL; + if (!menu_stack_.empty()) { + // We're running nested menus. Only exit all if the mouse wasn't over one + // of the menus from the last run. + MenuPart last_part = GetMenuPartByScreenCoordinateUsingMenu( + menu_stack_.back().first.item, screen_loc); + if (last_part.type != MenuPart::NONE) + exit_type = EXIT_OUTERMOST; + } + Cancel(exit_type); + +#if defined(OS_CHROMEOS) + // We're going to exit the menu and want to repost the event so that is + // is handled normally after the context menu has exited. We call + // RepostEvent after Cancel so that event capture has been released so + // that finding the event target is unaffected by the current capture. + RepostEvent(source, event, screen_loc, native_view, window); +#endif +} + void MenuController::SetDropMenuItem( MenuItemView* new_target, MenuDelegate::DropPosition new_position) {
diff --git a/ui/views/controls/menu/menu_controller.h b/ui/views/controls/menu/menu_controller.h index 4325e64..12af0aa 100644 --- a/ui/views/controls/menu/menu_controller.h +++ b/ui/views/controls/menu/menu_controller.h
@@ -503,7 +503,15 @@ // On non-aura Windows, a new mouse event is generated and posted to // the window (if there is one) at the location of the event. On // aura, the event is reposted on the RootWindow. - void RepostEvent(SubmenuView* source, const ui::LocatedEvent* event); + void RepostEvent(SubmenuView* source, + const ui::LocatedEvent* event, + const gfx::Point& screen_loc, + gfx::NativeView native_view, + gfx::NativeWindow window); + + // For Windows and Aura we repost an event which dismisses the |source| menu. + // The menu is also canceled dependent on the target of the event. + void RepostEventAndCancel(SubmenuView* source, const ui::LocatedEvent* event); // Sets the drop target to new_item. void SetDropMenuItem(MenuItemView* new_item,
diff --git a/ui/views/controls/menu/menu_controller_unittest.cc b/ui/views/controls/menu/menu_controller_unittest.cc index 03ba671..e9074f0 100644 --- a/ui/views/controls/menu/menu_controller_unittest.cc +++ b/ui/views/controls/menu/menu_controller_unittest.cc
@@ -9,9 +9,14 @@ #include "build/build_config.h" #include "ui/aura/scoped_window_targeter.h" #include "ui/aura/window.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" #include "ui/events/event_handler.h" +#include "ui/events/event_utils.h" #include "ui/events/null_event_targeter.h" #include "ui/events/test/event_generator.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" #include "ui/views/controls/menu/menu_controller_delegate.h" #include "ui/views/controls/menu/menu_delegate.h" #include "ui/views/controls/menu/menu_item_view.h" @@ -386,6 +391,11 @@ menu_controller_->set_is_combobox(is_combobox); } + void SetSelectionOnPointerDown(SubmenuView* source, + const ui::LocatedEvent* event) { + menu_controller_->SetSelectionOnPointerDown(source, event); + } + void RunMenu() { menu_controller_->message_loop_depth_++; menu_controller_->RunMessageLoop(false); @@ -825,6 +835,81 @@ EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); } +// Tests that an asynchronous menu nested within a synchronous menu does not +// crash when trying to repost events that occur outside of the bounds of the +// menu. Instead a proper shutdown should occur. +TEST_F(MenuControllerTest, AsynchronousRepostEvent) { + MenuController* controller = menu_controller(); + TestMenuControllerDelegate* delegate = menu_controller_delegate(); + scoped_ptr<TestMenuControllerDelegate> nested_delegate( + new TestMenuControllerDelegate()); + + ASSERT_FALSE(IsAsyncRun()); + + controller->AddNestedDelegate(nested_delegate.get()); + controller->SetAsyncRun(true); + + EXPECT_TRUE(IsAsyncRun()); + EXPECT_EQ(nested_delegate.get(), GetCurrentDelegate()); + + MenuItemView* item = menu_item(); + int mouse_event_flags = 0; + MenuItemView* run_result = + controller->Run(owner(), nullptr, item, gfx::Rect(), MENU_ANCHOR_TOPLEFT, + false, false, &mouse_event_flags); + EXPECT_EQ(run_result, nullptr); + + // Show a sub menu to targert with a pointer selection. However have the event + // occur outside of the bounds of the entire menu. + SubmenuView* sub_menu = item->GetSubmenu(); + sub_menu->ShowAt(owner(), item->bounds(), false); + gfx::Point location(sub_menu->bounds().bottom_right()); + location.Offset(1, 1); + ui::MouseEvent event(ui::ET_MOUSE_PRESSED, location, location, + ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0); + + // When attempting to select outside of all menus this should lead to a + // shutdown. This should not crash while attempting to repost the event. + SetSelectionOnPointerDown(sub_menu, &event); + + EXPECT_FALSE(IsAsyncRun()); + EXPECT_EQ(delegate, GetCurrentDelegate()); + EXPECT_EQ(0, delegate->on_menu_closed_called()); + EXPECT_EQ(1, nested_delegate->on_menu_closed_called()); + EXPECT_EQ(nullptr, nested_delegate->on_menu_closed_menu()); + EXPECT_EQ(0, nested_delegate->on_menu_closed_mouse_event_flags()); + EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE, + nested_delegate->on_menu_closed_notify_type()); + EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type()); +} + +// Tests that an asynchronous menu reposts touch events that occur outside of +// the bounds of the menu, and that the menu closes. +TEST_F(MenuControllerTest, AsynchronousTouchEventRepostEvent) { + MenuController* controller = menu_controller(); + TestMenuControllerDelegate* delegate = menu_controller_delegate(); + controller->SetAsyncRun(true); + + // Show a sub menu to targert with a touch event. However have the event occur + // outside of the bounds of the entire menu. + MenuItemView* item = menu_item(); + SubmenuView* sub_menu = item->GetSubmenu(); + sub_menu->ShowAt(owner(), item->bounds(), false); + gfx::Point location(sub_menu->bounds().bottom_right()); + location.Offset(1, 1); + ui::TouchEvent event(ui::ET_TOUCH_PRESSED, location, 0, 0, + ui::EventTimeForNow(), 0, 0, 0, 0); + controller->OnTouchEvent(sub_menu, &event); + + EXPECT_FALSE(IsShowing()); + EXPECT_EQ(1, delegate->on_menu_closed_called()); + EXPECT_EQ(nullptr, delegate->on_menu_closed_menu()); + EXPECT_EQ(0, delegate->on_menu_closed_mouse_event_flags()); + EXPECT_EQ(internal::MenuControllerDelegate::NOTIFY_DELEGATE, + delegate->on_menu_closed_notify_type()); + EXPECT_EQ(MenuController::EXIT_ALL, controller->exit_type()); +} + // Tests that if you exit all menus when an asynchrnous menu is nested within a // synchronous menu, the message loop for the parent menu finishes running. TEST_F(MenuControllerTest, AsynchronousNestedExitAll) {
diff --git a/win8/delegate_execute/command_execute_impl.cc b/win8/delegate_execute/command_execute_impl.cc index 2711336b..bae9ee8 100644 --- a/win8/delegate_execute/command_execute_impl.cc +++ b/win8/delegate_execute/command_execute_impl.cc
@@ -66,44 +66,6 @@ return S_OK; } -bool LaunchChromeBrowserProcess() { - base::FilePath delegate_exe_path; - if (!PathService::Get(base::FILE_EXE, &delegate_exe_path)) - return false; - - // First try and go up a level to find chrome.exe. - base::FilePath chrome_exe_path = - delegate_exe_path.DirName() - .DirName() - .Append(chrome::kBrowserProcessExecutableName); - if (!base::PathExists(chrome_exe_path)) { - // Try looking in the current directory if we couldn't find it one up in - // order to support developer installs. - chrome_exe_path = - delegate_exe_path.DirName() - .Append(chrome::kBrowserProcessExecutableName); - } - - if (!base::PathExists(chrome_exe_path)) { - AtlTrace("Could not locate chrome.exe at: %ls\n", - chrome_exe_path.value().c_str()); - return false; - } - - base::CommandLine cl(chrome_exe_path); - - // Prevent a Chrome window from showing up on the desktop. - cl.AppendSwitch(switches::kSilentLaunch); - - // Tell Chrome to connect to the Metro viewer process. - cl.AppendSwitch(switches::kViewerConnect); - - base::LaunchOptions launch_options; - launch_options.start_hidden = true; - - return base::LaunchProcess(cl, launch_options).IsValid(); -} - } // namespace bool CommandExecuteImpl::path_provider_initialized_ = false;